(ADSIS80_014)
impedance mismatch
impedance mismatch
De acordo com a documentação oficial do Hibernate diz que:
A impedância objeto-relacional, por vezes chamada de incompatibilidade de paradigmas, é apenas uma maneira elegante de dizer que modelos de objetos e relacionais não funcionam muito bem juntos.
Modelos de bancos de dados relacionais representam dados em formato tabular ao passo que linguagens como Java tratam isso de forma interconectada por meio de objetos
impedance mismatch
impedance mismatch
X
operações transacionais
operações
Relacional x OLAP x NoSQL
Object-Relational Mapping
Object-Relational Mapping
Object-Relational Mapping
Object-Relational Mapping
Object-Relational Mapping
Object-Relational Mapping
Object-Relational Mapping
Premissa: Mapear uma classe em uma tabela?
essa não é uma regra que pode ser seguida ao pé da letra, pois existem outras considerações a serem feitas (tipos dos dados, tamanho dos campos, entre outras)
Object-Relational Mapping
Todas as tabelas (ou relações) devem ter uma chave primária.
Object-Relational Mapping
Mapeamento de atributos.
Object-Relational Mapping
Mapeamento de atributos.
Object-Relational Mapping
Herança
Object-Relational Mapping
1º - Criar uma tabela para cada classe.
Object-Relational Mapping
1º - Criar uma tabela para cada classe.
Object-Relational Mapping
2º - Criar uma única tabela para toda a hierarquia de classes.
Object-Relational Mapping
2º - Criar uma única tabela para toda a hierarquia de classes.
Object-Relational Mapping
3º - Criar uma tabela para cada classe concreta.
Object-Relational Mapping
3º - Criar uma tabela para cada classe concreta.
Object-Relational Mapping
Associações Muitos-para-Muitos
Object-Relational Mapping
Associações Muitos-para-Muitos
Object-Relational Mapping
Associações Muitos-para-Muitos com Classe de Associação
Object-Relational Mapping
Associações Muitos-para-Muitos com Classe de Associação
Object-Relational Mapping
Associações Um-para-Muitos
Object-Relational Mapping
Associações Um-para-Muitos
Object-Relational Mapping
Associações Um-para-Muitos com Classe de Associação
Object-Relational Mapping
Associações Um-para-Muitos com Classe de Associação
Object-Relational Mapping
Associações Um-para-Um
Object-Relational Mapping
Associações Um-para-Um
Object-Relational Mapping
Associações Um-para-Um
Object-Relational Mapping
Associações Um-para-Um
Object-Relational Mapping
Associações Um-para-Um
Object-Relational Mapping
Associações Um-para-Um
Object-Relational Mapping
Associações Um-para-Um
Object-Relational Mapping
Associações Um-para-Um
Object-Relational Mapping
Associações Um-para-Um
o mágico
$ npm install --save mysql2o mágico
const mysql = require('mysql2');
const connection = mysql.createConnection({
host: "localhost",
user: "root",
password: "root",
database: "teste"
});
connection.query(
'SELECT * FROM users', (err, result, fields) => {
console.log(fields);
console.log(result);
});Consulta simples
Modelar objetos com JS para representar o atendimento de um Petshop.
Create Read Update Delete
Mapear os objetos para persistir e recuperar no Petshop.
// TODO - Implementar métodos do CRUD - Create Read Update Delete
// CREATE => INSERT INTO telefone VALUES ...
// READ => SELECT telefone VALUES ...
// UPDATE => UPDATE telefone SET ... WHERE ...
// DELETE => DELETE telefone WHERE ...- public/
-- css/
--- styles.css
- src
-- routes.js
-- server.js
- views/
-- layout.ejs
--- pages/
---- home.ejs$ mkdir petshop
$ npm install --save yarn -g
$ yarn init
# prencher dados$ yarn add express
$ yarn add ejs
$ yarn add express-ejs-layouts
$ yarn add body-parser
$ yarn add nodemon -D| express | É o pacote mais simples para criarmos as rotas do nosso app |
| ejs | É o pacote responsável pela engine EJS |
| express-ejs-layouts | Usamos ele para conseguirmos enviar dados para nossas páginas ejs pelo express. |
| nodemon | Pacote usado para subir sua aplicação com a vantagem de que a cada vez que alterar ou criar um arquivo js ele reinicia automaticamente. |
| body-parser | middleware para tratar as requisições antes de ser manipulada |
"scripts": {
"dev": "nodemon src/server.js"
},
"dependencies": {
"body-parser": "^1.19.0",
"ejs": "^3.0.1",
"express": "^4.17.1",
"express-ejs-layouts": "^2.5.0"
},
"devDependencies": {
"nodemon": "^2.0.2"
}package.json
const express = require('express')
const bodyParser = require('body-parser')
const expressLayouts = require('express-ejs-layouts')
const app = express()
const port = process.env.PORT || 3000
const routes = require('./routes')src/server.js
Variáveis globais
app.set('view engine', 'ejs')
app.use(expressLayouts)
app.use(bodyParser.urlencoded())
app.use(express.static(__dirname + '/public'))
app.use(routes)
app.listen(port, () => {
console.log(`Petshop is on http://localhost:${port}`)
})src/server.js
Configurações
const express = require('express')
const routes = express.Router()
routes.get('/', (req, res) => {
res.render('pages/home');
});
module.exports = routes;src/routes.js
Rotas
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="Protótipo">
<meta name="author" content="MentorsTec">
<link rel="icon" href="/docs/4.0/assets/img/favicons/favicon.ico">
<title>Petshop-ADS</title>
<link rel="canonical" href="https://getbootstrap.com/docs/4.0/examples/jumbotron/">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<style>
</style>
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
<a class="navbar-brand" href="#">Cesumar</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault"
aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="/">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="sobre">Sobre <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="/contato">Contato <span class="sr-only">(current)</span></a>
</li>
</ul>
</div>
</nav>
<main role="main">
<div class="jumbotron">
<div class="container">
<h1 class="display-3">Petshop</h1>
<p>...</p>
</div>
</div>
<div class="container">
<%- body %>
</div>
</main>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@9"></script>
</body>
</html>views/layout.ejs
Template base
<%- contentFor('body') %>
<h1>Clientes</h1>
<div class="row">
<div class="col-xs-1-12 p-2">
<div class="card">
<img class="card-img-top" src="https://picsum.photos/id/237/200/300" alt="Card image cap">
<div class="card-body">
<h5 class="card-title">Henrique Vignando</h5>
<p class="card-text">CPF/CNPJ: 070.824.859-48</p>
<a href="#" class="btn btn-primary">Editar</a>
</div>
</div>
</div>
</div>views/page/home.ejs
Pagina usando template
$ yarn devrun...
Principais Características
$ npm install --save sequelize
$ npm install --save mysql2$ yarn add sequelize
# Instalação do driver
$ yarn add pg pg-hstore # Postgres
$ yarn add mysql2 # MySQL
$ yarn add mariadb # MariaDB
$ yarn add sqlite3 # SQLite
$ yarn add tedious # Microsoft SQL Server
$ yarn add sequelize-cli -D- src
-- config
--- databas.js
-- database
--- migrations
--- index.js
- .sequelizercmodule.exports = {
dialect: 'mysql',
host: 'localhost',
username: 'root',
password: 'root',
database: 'petshop_ads',
define: {
timestamps: true,
underscored: true,
},
};config/database.js
Configuração de conexão
const Sequilize = require('sequelize');
const dbConfig = require('../config/database');
const connection = new Sequilize(dbConfig);
module.exports = connection;database/index.js
Passando a conexão para nossa app
const path = require('path')
module.exports = {
config: path.resolve(__dirname, 'src', 'config', 'database.js'),
'migrations-path': path.resolve(__dirname, 'src', 'database', 'migrations')
}.sequelizerc
Configuração do Sequelize
$ yarn sequelize migration:create --name=cria-clienteCriando arquivo de migração
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('clientes', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
nome: {
type: Sequelize.STRING,
allowNull: false,
},
sobrenome: {
type: Sequelize.STRING,
allowNull: true,
},
email: {
type: Sequelize.STRING,
allowNull: false,
},
created_at: {
type: Sequelize.DATE,
allowNull: false,
},
updated_at: {
type: Sequelize.DATE,
allowNull: false,
},
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('users');
}
};
<timestemp>-cria-cliente.js
Criando arquivo de migração
$ yarn sequelize db:create
$ yarn sequelize db:migrateGerando banco e tabela no DB
const { Model, DataTypes } = require('sequelize');
const connection = require('../database')
class Cliente extends Model {
static init(sequelize) {
super.init({
nome: DataTypes.STRING,
sobrenome: DataTypes.STRING,
email: DataTypes.STRING,
}, {
sequelize,
})
}
}
Cliente.init(connection);
module.exports = Cliente;Cliente.js
Criando arquivo de Classe
- src
-- models
--- Cliente.jsconst express = require("express");
const routes = express.Router();
const Cliente = require("./models/Cliente");
routes.get("/", async (req, res) => {
const henrique = await Cliente.create({
nome: "Henrique",
sobrenome: "Vignando",
email: "rickuev@gmail.com",
});
res.render("pages/home", {cliente: henrique});
});
module.exports = routes;src/routes.js
Instanciando Cliente
<%- contentFor('body') %>
<h1>Clientes</h1>
<div class="row">
<div class="col-xs-1-12 p-2">
<div class="card">
<img class="card-img-top" src="https://via.placeholder.com/250"
alt="Card image cap">
<div class="card-body">
<h5 class="card-title">
<%= cliente.nome %> <%= cliente.sobrenome %>
</h5>
<p class="card-text"><%= cliente.email %> </p>
<a href="#" class="btn btn-primary">Editar</a>
</div>
</div>
</div>
</div>views/page/home.ejs
Instanciando Cliente
Mapear -CRUD- os objetos (Cliente, Fornecedor, Endereço e Telefone) para persistir e recuperar no projeto NodeJs Petshop usando ORM Sequelize.
Benefícios importantes em dividir um sistema em camadas:
Desvantagens da arquitetura em camadas:
Desvantagens da arquitetura em camadas:
A parte mais difícil de uma arquitetura em camadas é decidir quais camadas ter e qual deve ser a responsabilidade de cada camada.
Arquitetura de um sistema tem diversos elementos como:
É considerado como um padrão de projeto, uma solução já testada e documentada que possa resolver um problema específico em projetos distintos.
O uso de algum padrão de projeto pode trazer alguns benefícios:
Mais benefícios:
Engenharia de Software - 7.ed.: Os Paradigmas Clássico e Orientado a Objetos - Yourdon, Constantine e Myers
Acoplamento: “O acoplamento é uma medida da interconexão entre os módulos de uma estrutura de software, depende da complexidade de interface entre módulos”;
Coesão: "Um módulo coeso executa uma única tarefa dentro do procedimento de software, exigindo pouca interação com procedimentos executados em outras partes de um programa."
PRESSMAN, Roger; MAXIM, Bruce. Engenharia de Software-8ª Edição. McGraw Hill Brasil, 2016.
A utilização do padrão MVC trás como maior benefício isolar as regras de negócios da lógica de apresentação, a interface com o usuário. Isto possibilita a existência de várias interfaces com o usuário que podem ser modificadas sem que haja a necessidade da alteração das regras de negócios, proporcionando assim muito mais flexibilidade e oportunidades de reuso das regras de negócio.
Uma possível implementação de Model View Controller para aplicações Web.
| Padrão MVC | Padrão MTV |
|---|---|
| Model(MVC) | Model(MTV) |
| View(MVC) | Template(MTV) |
| Controller(MVC) | View(MTV) |
Uma boa razão pela qual os desenvolvedores não preocupam tanto com concorrência é por conta dos os gerenciadores de transações (ex. Banco de dados).
Perda de Atualizações (Lost updates) nos CVS: digamos que Martin edite um arquivo para fazer algumas alterações no método checkConcurrency - uma tarefa que leva alguns minutos. Enquanto ele faz isso, David altera o método updateImportantParameter no mesmo arquivo. David inicia e termina sua alteração muito rapidamente, tão rapidamente que, embora ele comece depois de Martin, ele termina antes dele. Quando Martin leu o arquivo, ele não incluía a atualização de David; portanto, quando Martin escreve no arquivo, ele sobrescreve a versão de David e a atualização de David se perde para sempre.
Leitura inconsistente (Inconsistent read) ocorre quando você lê duas coisas que são informações corretas, mas não corretas ao mesmo tempo. Martin quer saber quantas classes existem no pacote de concorrência, que contém dois subpacotes para bloqueio e multifase. Martin olha no pacote de bloqueio e vê sete classes. Nesse ponto, ele recebe um telefonema de Roy sobre alguma pergunta obscura. Enquanto Martin atende o telefone, David termina de lidar com esse bug no código de bloqueio de quatro fases e adiciona duas classes ao pacote de bloqueio e três classes às cinco que estavam no pacote multifásico. Ao terminar o telefonema, Martin olha no pacote multifásico para ver quantas classes existem e vê oito, produzindo um total geral de quinze.
Infelizmente, quinze classes nunca foram a resposta certa. A resposta correta foi doze antes da atualização de David e dezessete depois. Qualquer resposta teria sido correta, mesmo que não fosse atual, mas quinze nunca foram corretas. Esse problema é chamado de leitura inconsistente porque os dados que Martin leu eram inconsistentes.
Esses dois problemas causam uma falha de corretude (ou segurança) e resultam em comportamento incorreto que não teria ocorrido sem duas pessoas tentando trabalhar com os mesmos dados ao mesmo tempo.
O problema essencial de qualquer programação concorrente é que não basta se preocupar com a corretude; você também precisa se preocupar com a vivacidade: quanta atividade concorrente pode continuar. Muitas vezes, as pessoas precisam sacrificar alguma corretude para ganhar mais vivacidade, dependendo da seriedade e probabilidade das falhas e da necessidade de as pessoas trabalharem em seus dados concorrentemente.
Os problemas de concorrência já existem há algum tempo, e já existem várias soluções.
Para aplicativos corporativos, duas soluções são particularmente importantes: isolamento e imutabilidade
Problemas de concorrência ocorrem quando mais de um agente ativo, como um processo ou encadeamento, tem acesso ao mesmo pedaço de dados. Uma maneira de lidar com isso é o isolamento: particione os dados para que qualquer parte deles possa ser acessada apenas por um agente ativo.
Os processos funcionam assim na memória do sistema operacional: O sistema operacional aloca memória exclusivamente para um único processo, e somente esse processo pode ler ou escreva os dados vinculados a ele.
Um bom design de concorrência é encontrar maneiras de garantir que o máximo de programação possível seja feito em uma região isolada de concorrência.
Outro problema é se os dados compartilhandos puderem ser modificados.
Uma maneira de evitar conflitos de concorrência são dados imutáveis.
Ao identificar alguns dados imutáveis, ou pelo menos imutáveis quase o tempo todo, podemos tranquilizar as preocupações de concorrência e compartilhá-los amplamente.
O que acontece quando temos dados mutáveis que não podemos isolar? Em termos gerais, existem duas formas de controle de concorrência que podemos usar: otimista e pessimista.
Vamos supor que Martin e David desejem editar o arquivo do cliente ao mesmo tempo.
Com o bloqueio otimista, os dois podem fazer uma cópia do arquivo e editá-lo livremente. Se Davi for o primeiro a terminar, ele poderá verificar seu trabalho sem problemas. O controle de simultaneidade entra em ação quando Martin tenta confirmar suas alterações. Nesse ponto, o sistema de controle do código-fonte detecta um conflito entre as alterações de Martin e as de David. O comprometimento de Martin é rejeitado e cabe a ele descobrir como lidar com a situação.
Com o bloqueio pessimista, quem faz o check-out do arquivo primeiro impede que outras pessoas o editem. Portanto, se Martin for o primeiro a fazer o check-out, David não poderá trabalhar com o arquivo até que Martin termine e confirme suas alterações.
Uma maneira de pensar sobre isso é que um bloqueio otimista é sobre detecção de conflitos, enquanto um bloqueio pessimista é sobre prevenção de conflitos.
Ambas as abordagens têm seus prós e contras.
O problema com o bloqueio pessimista é que ele reduz a simultaneidade. Enquanto Martin está trabalhando em um arquivo, ele bloqueia, então todo mundo tem que esperar
Bloqueios otimistas permitem que as pessoas progridam muito melhor, porque o bloqueio é mantido apenas durante a confirmação. O problema com eles é o que acontece quando você entra em conflito. Basicamente, todo mundo após a confirmação de David precisa verificar a versão do arquivo que David fez check-in.
A essência da escolha entre bloqueios otimistas e pessimistas é a frequência e a gravidade dos conflitos.
Se os conflitos são suficientemente raros, ou se as consequências não são um grande problema, você deve escolher bloqueios otimistas, pois eles oferecem melhor concorrência e geralmente são mais fáceis de implementar.
No entanto, se os resultados de um conflito forem dolorosos para os usuários, você precisará usar uma técnica pessimista.
Considere esta situação. Martin edita a classe Customer, que faz chamadas na classe Order. Enquanto isso, David edita a classe Order e altera a interface. David compila e faz commit; Martin então compila e faz commit. Agora, o código compartilhado está quebrado porque Martin não percebeu que a classe Order foi alterada depois da alteração dele. Alguns sistemas de controle de código-fonte detectam essa leitura inconsistente, mas outros exigem algum tipo de disciplina manual para reforçar a consistência, como atualizar seus arquivos do branch antes de fazer o commit.
Em essência, esse é o problema de leitura inconsistente e geralmente é fácil ocorrer, porque a maioria das pessoas tende a se concentrar nas atualizações perdidas como o problema essencial na concorrência
Os bloqueios pessimistas lidam com esse problema por meio de bloqueios de leitura e gravação
Para ler dados, você precisa de um bloqueio de leitura (ou compartilhamento)
Para gravar dados, você precisa de um bloqueio de gravação (ou exclusivo)
Bloqueios otimistas geralmente baseiam sua detecção de conflito em algum tipo de marcador de versão nos dados
Pode ser um marcação de data/hora ou um contador sequencial
Para detectar atualizações perdidas, o sistema verifica se o marcador de versão da sua atualização com o marcador de versão dos dados compartilhados. Se eles são iguais, o sistema permite a atualização e atualiza o marcador da versão
A detecção de uma leitura inconsistente é essencialmente semelhante, todos os dados lidos também precisam ter seu marcador de versão comparado com os dados compartilhados. Quaisquer diferenças indicam um conflito.
Outra maneira de lidar com problemas de leitura inconsistentes é usar as leituras temporais
Estes prefixam cada leitura de dados com algum tipo de carimbo de data/hora ou rótulo imutável, e o banco de dados retorna os dados como estavam de acordo com esse horário ou rótulo.
Poucos bancos de dados têm algo parecido com isso, mas os desenvolvedores geralmente se deparam com isso nos sistemas de controle de código-fonte
O problema é que a fonte de dados precisa fornecer um histórico temporal completo das mudanças, o que leva tempo e espaço para processar
Isso é razoável para o código fonte, mas é mais difícil e mais caro para bancos de dados.
Um problema específico com técnicas pessimistas é o deadlock
Digamos que Martin comece a editar o arquivo Cliente e David comece a editar o arquivo Pedido. David percebe que, para concluir sua tarefa, ele também precisa editar o arquivo Cliente, mas Martin tem um bloqueio para que ele tenha que esperar. Então Martin percebe que precisa editar o arquivo Pedidos, que David bloqueou. Eles agora estão em um deadlock - nenhum deles pode progredir até que o outro seja concluído.
Descritos dessa maneira, os deadlocks parecem fáceis de evitar, mas podem ocorrer com muitas pessoas envolvidas em uma cadeia complexa, e os torna mais complicados.
Outra alternativa seria, se Martin tentar adquirir uma lock e David já tiver uma, Martin se tornará automaticamente uma vítima. É uma técnica drástica, mas é simples de implementar. E, em muitos casos, esse esquema funciona muito bem.
Um sistema distribuído é aquele no qual os componentes localizados em computadores interligados em rede se comunicam e coordenam suas ações apenas passando mensagens
Coulouris et al. 2007
RPC encapsula uma chamada remota em uma chamada de método/função remoto representados pela abordagem SOA.
REST se preocupa com as operações disponíveis já estão representadas pelos verbos de requisição do protocolo HTTP.
Curiosidade: é muito mais comum encontrar uma API RPC-like do que REST.
Criar as telas de -CRUD- para os objetos Cliente, Fornecedor, Endereço e Telefone.
Finalizar as telas de -CRUD- e relacionamentos para os objetos Cliente, Fornecedor, Endereço e Telefone.
O Petshop tem produtos para ser vendidos aos clientes. Uma venda pode ter mais de um produto.
O produtos estão armazenados em um estoque, que é abastecido pelas compras feitas dos fornecedores.
Agora o Petshop também oferece serviços aos seus clientes, como banho&tosa.
Esses serviços devem sem agendados previamente