minhas informações de contato
Correspondência[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
JavaWeb (1: Conhecimento básico e construção de ambiente)https://blog.csdn.net/xpy2428507302/article/details/140365130?spm=1001.2014.3001.5501JavaWeb (2: Servlet e Jsp, ouvinte e filtro)
https://blog.csdn.net/xpy2428507302/article/details/140365159?spm=1001.2014.3001.5501
Índice
7. Conjunto de conexões de banco de dados
11. Arquitetura MVC de três camadas
2. Arquitetura mvc de três camadas
JDBC (Java DataBase Connectivity): tecnologia de conexão de banco de dados Java
JDBC é um sistema de gerenciamento independente de um banco de dados específico e uma interface pública para acesso e operações universais de banco de dados SQL.
Define um conjunto de padrões para fornecer uma maneira unificada de acessar diferentes bancos de dados.
JDBC é uma API de aplicação para acesso a banco de dados, composta por um conjunto de classes e interfaces escritas em linguagem Java.
Inclui dois níveis:
① API orientada a aplicativos para os programadores chamarem.
② API orientada a banco de dados para fabricantes desenvolverem drivers de banco de dados.
Para conectar diferentes bancos de dados com JDBC, você só precisa carregar diferentes pacotes de drivers de banco de dados e não precisa se preocupar com as diferenças nas linguagens operacionais do banco de dados.
① Criar tabela de banco de dados
- CREATE TABLE users(
- id INT PRIMARY KEY,
- `name` VARCHAR(40),
- `password` VARCHAR(40),
- email VARCHAR(60),
- birthday DATE
- );
- INSERT INTO users(id,`name`,`password`,email,birthday)
- INSERT INTO users(id,`name`,`password`,email,birthday)
- INSERT INTO users(id,`name`,`password`,email,birthday)
- SELECT * FROM users;
② Importar dependências de banco de dados
- <!--mysql的驱动-->
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>8.0.31</version>
- </dependency>
③ Uso de JDBC:
Ⅰ Carregue o driver do banco de dados (a ponte entre o programa java e o banco de dados)
Ⅱ Obtenha Conexão, uma conexão entre o programa java e o banco de dados
Ⅲ Crie um objeto Statement que envia SQL para o banco de dados, gerado pelo Connection.
Ⅳ Escreva instruções SQL (escreva SQLs diferentes de acordo com o negócio)
Ⅴ. Execute SQL (se desejar receber o valor de retorno, crie um objeto ResultSet para salvar os resultados da consulta após a execução da instrução)
Ⅵ. Feche a conexão.
- public class JDBCTest {
- public static void main(String[] args) throws Exception {
- //配置信息
- //要连接的数据库URL(解决中文乱码问题:useUnicode=true&characterEncoding=utf8&useSSL=true)
- String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
- //连接的数据库时使用的用户名
- String username = "root";
- //连接的数据库时使用的密码
- String password = "123456";
- Connection conn = null;
- Statement st = null;
- ResultSet rs = null;
-
- try {
- //1.加载驱动
- Class.forName("com.mysql.cj.jdbc.Driver");
- //2.获取与数据库的链接
- conn = DriverManager.getConnection(url, username, password);
- //3.获取用于向数据库发送sql语句的statement对象
- st = conn.createStatement();
- String sql = "select id,name,password,email,birthday from users";
- //4.向数据库发sql,并获取代表结果集的resultset对象
- //查:executeQuery 增删改:executeUpdate
- rs = st.executeQuery(sql);
- //5.取出结果集的数据
- while (rs.next()) {
- System.out.println("id=" + rs.getInt("id"));
- System.out.println("name=" + rs.getString("name"));
- System.out.println("password=" + rs.getString("password"));
- System.out.println("email=" + rs.getString("email"));
- System.out.println("birthday=" + rs.getDate("birthday"));
- }
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- try {
- //6.关闭链接,释放资源(先开后关)
- rs.close();
- st.close();
- conn.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
- }
jdbc:mysql://localhost:3306/xxx
jdbc | protocolo |
mysql | subprotocolo |
host local:3306 | anfitrião:porta |
xxx | base de dados |
Como escrever endereços URL de banco de dados comumente usados:
Connection é usado para representar links de banco de dados e Collection é o objeto mais importante na programação de banco de dados.
Todas as interações entre o cliente e o banco de dados são concluídas através do objeto de conexão., métodos comuns deste objeto:
criarDeclaração() | Crie um objeto de instrução que envie sql para o banco de dados |
prepareStatement(sql) | Crie um objeto PrepareSatement que envia sql pré-compilado para o banco de dados |
setAutoCommit(booleano autoCommit) | Defina se as transações serão confirmadas automaticamente |
comprometer-se() | Enviar transação no link |
reverter() | Transação de reversão neste link |
O objeto Statement é usado para enviar instruções SQL ao banco de dados. Métodos comuns do objeto Statement:
executeQuery(String sql) | Usado para enviar instruções de consulta aos dados e retornar um conjunto de resultados ResultSet |
executeUpdate(String sql) | Usado para enviar instruções de inserção, atualização ou exclusão ao banco de dados e retornar o número de linhas atualizadas no banco de dados |
executar(String sql) | Usado para enviar instruções SQL arbitrárias ao banco de dados |
adicionarBatch(String sql) | Coloque várias instruções SQL em um lote |
executarBatch() | Envie um lote de instruções SQL ao banco de dados para execução |
Perceber:
Para melhorar a eficiência operacional, o método execute geralmente não é usado diretamente.
Em vez disso, use-os adequadamente: executeQuery para consultas executeUpdate para adições, exclusões e modificações.
ResultSet é usado para representar os resultados de execução de instruções SQL.
Conjunto de resultados Ao encapsular o conjunto de resultados de execução, usesemelhante à mesaO caminho。
O objeto ResultSet mantém um cursor apontando para as linhas de dados da tabela.Inicialmente, o cursor está antes da primeira linha。
Chamar o método ResultSet.next() pode fazer o cursor apontar para uma linha de dados específica e chamar o método getxxx para obter os dados da linha.
① Obtenha qualquer tipo de dados
obterObjeto(int índice) | Obtenha o objeto Object de acordo com o número especificado de colunas |
getObject(string nomedacoluna) | Obtenha o objeto Object de acordo com o nome do atributo especificado |
② Obtenha dados do tipo especificado, como obter o tipo String
getString(int índice) | Obtenha um objeto String com base no número especificado de colunas |
getString(String nomedacoluna) | Obtenha o objeto String de acordo com o nome do atributo especificado |
③ Como rolar o conjunto de resultados:
próximo() | passar para a próxima linha |
Anterior() | ir para a linha anterior |
absoluto(int linha) | Mover para a linha especificada |
antesPrimeiro() | Mova a frente do resultSet |
depoisÚltimo() | Vá para o final do resultSet |
Após a execução do programa Jdbc, lembre-se de liberar os objetos criados pelo programa para interagir com o banco de dados durante o processo de execução.
Esses objetos geralmente são objetos ResultSet, Statement e Connection.
Principalmente o objeto Connection, é um recurso muito raro e deve ser liberado imediatamente após o uso.
Se a conexão não puder ser fechada imediata e corretamente, isso poderá facilmente levar à inatividade do sistema.
Para garantir que o código de liberação de recursos possa ser executado, o código de liberação de recursos também deve ser colocado na instrução finalmente.
Existem dois problemas ao usar a Declaração para desenvolvimento:
① As strings precisam ser emendadas com frequência e a taxa de erro é alta
- String username = "zhangsan";
- String password = "123";
- String sql = "select * from users where name='"+username+"' and password='"+password+"'";
- ResultSet rs = st.executeQuery(sql);
② Existe um risco potencial de injeção de SQL
Injeção de SQL: Injetar instruções SQL ilegais nos dados inseridos pelo usuário, usando técnicas inteligentes para unir strings, causando um curto-circuito SQL, roubando assim os dados do banco de dados.
- public class SQLTest {
- public static void main(String[] args) throws Exception {
- // 正常登陆sql:select * from users where name='张三' and password ='123456'
- //login("张三","123456");
- // SQL 注入:select * from users where name='' and password ='123456' or '1'='1'
- login("", "123456' or '1'='1");
- }
-
- public static void login(String username, String password) throws Exception {
- String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
- String dbUsername = "root";
- String dbPassword = "123456";
-
- //1.加载驱动
- Class.forName("com.mysql.cj.jdbc.Driver");
- //2.获取与数据库的链接
- Connection conn = DriverManager.getConnection(url, dbUsername, dbPassword);
- //3.获取用于向数据库发送sql语句的statement
- Statement st = conn.createStatement();
- String sql = "select * from users where name='" + username + "' and password='" + password + "'";
- System.out.println(sql);
- //4.向数据库发sql,并获取代表结果集的rs
- ResultSet rs = st.executeQuery(sql);
- if (rs.next()) {
- System.out.println("登录成功");
- } else {
- System.out.println("登录失败");
- }
- //6.关闭链接,释放资源
- rs.close();
- st.close();
- conn.close();
- }
- }
resultado da operação:
Perceber:
A prioridade de e na instrução SQL é maior que ou, portanto o SQL executado é equivalente a select * from users where '1' = '1';
Solução:Use PreparedStatement, uma subclasse de Statement, que fornece a função de espaço reservado SQL.
Não há necessidade de emendar strings e os dados inseridos pelo usuário serão totalmente detectados, tornando-os mais seguros.
- public class PSTest {
- public static void main(String[] args) throws Exception {
- // 正常登陆sql:select * from users where name='张三' and password ='123456'
- //login("张三","123456");
- // SQL 注入:select * from users where name='' and password ='123456' or '1'='1'
- login("", "123456' or '1'='1");
- }
-
- public static void login(String username, String password) throws Exception {
- String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
- String dbUsername = "root";
- String dbPassword = "123456";
-
- Class.forName("com.mysql.cj.jdbc.Driver");
-
- Connection conn = DriverManager.getConnection(url, dbUsername, dbPassword);
- //获取用于向数据库发送预编译sql语句的prepareStatement
- String sql = "select * from users where name = ? and password = ?";
- System.out.println(sql);
- PreparedStatement ps = conn.prepareStatement(sql);
- //给占位符 ? 填充数据
- ps.setString(1, username);
- ps.setString(2, password);
- ResultSet rs = ps.executeQuery();
- if (rs.next()) {
- System.out.println("登录成功");
- } else {
- System.out.println("登录失败");
- }
- rs.close();
- ps.close();
- conn.close();
- }
- }
resultado da operação:
Uma transação refere-se a um conjunto lógico de operações, todas bem-sucedidas ou malsucedidas (princípio ACID).
Quando o programa Jdbc obtém um objeto Connection do banco de dados, por padrão o objeto Connection enviará automaticamente uma transação ao banco de dados.
Se desejar desativar esse método de envio padrão e permitir que vários SQLs sejam executados em uma transação, você poderá usar a seguinte instrução de transação de controle JDBC.
Conexão.setAutoCommit(falso); | iniciar transação |
Conexão.rollback(); | Transação de reversão |
Conexão.commit(); | confirmar transação |
① Criar tabela de contas
- /*创建账户表*/
- CREATE TABLE account(
- id INT PRIMARY KEY AUTO_INCREMENT,
- NAME VARCHAR(40),
- money DECIMAL(9,2)
- );
- /*插入测试数据*/
- insert into account(name,money) values('A',1000);
- insert into account(name,money) values('B',1000);
- insert into account(name,money) values('C',1000);
② Simule o cenário de negócios quando a transferência for bem-sucedida
- //失败后让数据库自动回滚事务
- public class Demo {
- public static void main(String[] args) {
- String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
- String username = "root";
- String password = "123456";
- Connection conn = null;
- try {
- Class.forName("com.mysql.cj.jdbc.Driver");
- conn = DriverManager.getConnection(url, username, password);
-
- //通知数据库开启事务,false表示开启
- conn.setAutoCommit(false);
-
- String sql1 = "update account set money=money-100 where name = 'A' ";
- conn.prepareStatement(sql1).executeUpdate();
-
- //模拟执行完SQL1之后程序出现了异常而导致后面的SQL无法正常执行,事务也无法正常提交
- int x = 1/0;
-
- String sql2 = "update account set money=money+100 where name = 'B' ";
- conn.prepareStatement(sql2)executeUpdate();
-
- //sql1 和 sql2都顺利执行,就提交事务
- conn.commit();
- System.out.println("成功!!!");
- } catch (Exception e) {
- //出现异常,通知数据库回滚事务
- conn.rollback();
- e.printStackTrace();
- } finally {
- conn.close();
- }
- }
- }
Em diferentes solicitações, você precisa se conectar ao banco de dados e liberar recursos a cada vez, e muito código repetido será escrito.
Encapsule as operações de preparação e liberação da conexão com o banco de dados em uma classe de ferramenta e chame-a diretamente ao usá-la para evitar a gravação de código repetido.
- public class JdbcUtil {
- private static Connection connection;
- private static String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
- private static String username = "root";
- private static String password = "123456";
-
- //驱动(类)只需要加载一次,放静态代码块即可
- static {
- try {
- //加载数据库驱动
- Class.forName("com.mysql.cj.jdbc.Driver");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- // 获取数据库连接对象
- public static Connection getConnection() throws SQLException {
- return DriverManager.getConnection(url, username, password);
- }
-
- // 释放资源(利用多态:Statement 和 PreparedStatement 都可以传进来)
- public static void release(Connection conn, Statement st, ResultSet rs) {
- try {
- if (rs != null) {
- rs.close();
- }
- if (st != null) {
- st.close();
- }
- if (conn != null) {
- conn.close();
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
Caso de chamada, como: adicionar usuário
-
- public void add(String name, String password) {
- Connection conn = null;
- PreparedStatement ps = null;
- try {
- conn = JdbcUtil.getConnection();
- String sql = "insert into users(name,password) values(?,?)";
- ps = conn.prepareStatement(sql);
- ps.setString(1, name);
- ps.setString(2, password);
- ps.executeUpdate();
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- JdbcUtil.release(conn, ps, null);
- }
- }
Processo de desenvolvimento JDBC:
Ⅰ Carregue o driver do banco de dados (só precisa ser carregado uma vez)
Ⅱ Estabelecer conexão com o banco de dados (Conexão)
Ⅲ Crie um objeto Statement que envia SQL para o banco de dados, gerado pelo Connection.
Ⅳ. Escrevendo instruções SQL
Ⅴ. Executar SQL (Consulta -> objeto ResultSet recebe conjunto de resultados)
Ⅵ Feche a conexão e libere recursos.
O objeto de conexão com o banco de dados é obtido através do DriverManager. Cada vez que for obtido, você precisa se inscrever no banco de dados para obter uma conexão e verificar o nome de usuário e a senha.
Os usuários precisam obter um link do banco de dados para cada solicitação, e a criação de uma conexão com o banco de dados geralmente consome recursos relativamente grandes e leva muito tempo para ser criada.
Cada vez que a instrução SQL é executada, a conexão é desconectada, o que causará desperdício de recursos e os recursos de conexão do banco de dados não serão bem reutilizados.
Supondo que o site receba 100.000 visitas por dia, o servidor de banco de dados precisa criar 100.000 conexões, o que é um enorme desperdício de recursos de banco de dados e pode facilmente causar estouro de memória do servidor de banco de dados e expansão da máquina.
Solução: pool de conexões de banco de dados
A ideia básica do pool de conexões de banco de dados:
Estabeleça um buffer pool para o banco de dados e coloque um certo número de objetos de conexão no buffer pool antecipadamente.
Quando você deseja obter uma conexão com o banco de dados, você só precisa obter um objeto do buffer pool.
Após o uso, coloque-o novamente no buffer pool para a próxima solicitação, conseguindo a reutilização dos recursos sem a necessidade de criação repetida.
Quando não há objetos de conexão ociosos no pool de conexões do banco de dados, novas solicitações entrarão na fila de espera e aguardarão que outros threads liberem a conexão.
O pool de conexão de banco de dados JDBC é concluído usando a interface javax.sql.DataSource é a interface fornecida oficialmente por java.
Ao usá-lo, os desenvolvedores não precisam implementar a interface sozinhos e podem usar ferramentas de terceiros.
C3P0 é uma implementação de terceiros comumente usada. No desenvolvimento real, o C3P0 pode ser usado diretamente para completar a operação do pool de conexões de banco de dados.
Etapas para uso:
① Importar dependências em pom.xml
- <dependency>
- <groupId>com.mchange</groupId>
- <artifactId>c3p0</artifactId>
- <version>0.9.5.2</version>
- </dependency>
② Escreva o código
- public class DataSourceTest {
- public static void main(String[] args) {
- try {
- //创建C3P0数据库连接池
- ComboPooledDataSource dataSource=new ComboPooledDataSource();
- dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
- dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8");
- dataSource.setUser("root");
- dataSource.setPassword("123456");
- //设置初始化连接个数
- dataSource.setInitialPoolSize(5);
- //设置最大连接个数(连接池中不够,可以继续申请,申请后最终的上限)
- dataSource.setMaxPoolSize(20);
- //当连接对象不够时,再次申请的连接对象个数
- dataSource.setAcquireIncrement(5);
- //设置最小连接数(当连接池中剩余2个连接对象时,就去申请 --> 提前做准备)
- dataSource.setMinPoolSize(2);
- Connection conn=dataSource.getConnection();
-
- //SQL操作...
-
- //将连接还回到数据库连接池中
- conn.close();
- } catch (PropertyVetoException e) {
- e.printStackTrace();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
Perceber:
Conexão obtida através do método tradicional: com.mysql.cj.jdbc.ConnectionImpl@3c153a1
Conexão obtida por C3P0: com.mchange.v2.c3p0.impl.NewProxyConnection@6156496
então,Embora todos chamem o método close, as classes de implementação são diferentes, então a reescrita do método também é diferente.。
O método close em C3P0 não destrói diretamente o recurso de conexão, mas retorna a conexão ao pool de conexões do banco de dados.
O método acima de configuração de parâmetros para o conjunto de conexões de banco de dados é escrito diretamente no programa Java.
Isto é adotadoCódigo difícilO caminho,Cada vez que você altera a configuraçãoPrecisa recompilar, gere novos arquivos de classe, a eficiência é muito baixa。
No desenvolvimento real, as informações de configuração do C3P0 são definidas em um arquivo xml, e o programa Java só precisa carregar o arquivo de configuração para concluir a operação de inicialização do pool de conexões de banco de dados.
Posteriormente, você só precisa modificar a configuração e modificar a configuração em xml sem recompilar.
Etapas para uso:
① No diretório de recursos, crie um novo arquivo chamado c3p0-config.xml
② Preencha as informações de configuração em c3p0-config.xml:
- <?xml version="1.0" encoding="UTF-8"?>
- <c3p0-config>
- <!--配置连接池mysql-->
- <named-config name="C3P0Test">
- <!-- 指定连接数据源的基本属性 -->
- <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
- <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8</property>
- <property name="user">root</property>
- <property name="password">123456</property>
-
- <!-- 设置初始化连接个数 -->
- <property name="initialPoolSize">5</property>
- <!-- 设置最大连接个数(连接池中不够,可以继续申请,申请后最终的上限) -->
- <property name="maxPoolSize">20</property>
- <!-- 当连接对象不够时,再次申请的连接对象个数 -->
- <property name="acquireIncrement">5</property>
- <!-- 设置最小连接数(当连接池中剩余2个连接对象时,就去申请 -> 提前做准备) -->
- <property name="minPoolSize">2</property>
- </named-config>
- </c3p0-config>
③Escreva o programa Java
- public class DataSourceTest {
- public static void main(String[] args) {
- try {
- //创建C3P0数据库连接池
- ComboPooledDataSource dataSource=new ComboPooledDataSource("C3P0Test");
- Connection conn=dataSource.getConnection();
- System.out.println(conn);
- //将连接还回到数据库连接池中
- conn.close();
- }catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
Perceber:
① O parâmetro no método de construção ComboPooledDataSource é o valor do atributo name da tagnamed-config configurada em c3p0-config.xml.
② Neste momento, a classe da ferramenta JDBC pode ser modificada como:
- public class JdbcUtil {
- private static DataSource dataSource;
-
- static {
- dataSource = new ComboPooledDataSource("C3P0Test");
- }
-
- // 获取数据库连接对象
- public static Connection getConnection() throws SQLException {
- Connection conn = null;
- try {
- conn = dataSource.getConnection();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- return conn;
- }
-
- // 释放资源(利用多态:Statement 和 PreparedStatement 都可以传进来)
- public static void release(Connection conn, Statement st, ResultSet rs) {
- try {
- if (rs != null) {
- rs.close();
- }
- if (st != null) {
- st.close();
- }
- if (conn != null) {
- conn.close();
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
- public static Student findById(Integer idx) {
- Connection conn = null;
- PreparedStatement st = null;
- ResultSet rs = null;
- Student stu = null;
- try {
- conn = JdbcUtil.getConnection();
-
- String sql = "select * from student where id = ?";
- PreparedStatement ps = conn.prepareStatement(sql);
- //给占位符 ? 填充数据
- ps.setInt(1, idx);
- rs = ps.executeQuery();
- //取出结果集的数据
- while (rs.next()) {
- Integer id = rs.getInt(1);
- String name = rs.getString(2);
- Double score = rs.getDouble(3);
- Date birthday = rs.getDate(4);
- stu = new Student(id, name, score, birthday);
- }
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- try {
- //关闭链接,释放资源
- rs.close();
- st.close();
- conn.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- return stu;
- }
No código acima, as operações de preenchimento dos espaços reservados com dados e extração dos dados do conjunto de resultados são muito complicadas.
Se houver 100 atributos na tabela Student, teremos que escrever 100 linhas no loop while para recuperar os dados, e também podem ser necessárias muitas linhas para preencher os espaços reservados.
Solução:DBUtils pode ajudar os desenvolvedores a completar o encapsulamento de dados (mapeamento de conjuntos de resultados para objetos Java).
Etapas para uso:
① Importar dependências em pom.xml
- <dependency>
- <groupId>commons-dbutils</groupId>
- <artifactId>commons-dbutils</artifactId>
- <version>1.6</version>
- </dependency>
② Escreva o código
- public static Student findById(Integer idx) {
- Connection conn = null;
- Student stu = null;
- try {
- conn = JdbcUtil.getConnection();
-
- String sql = "select * from student where id = ?";
- //使用DBUtils
- QueryRunner qr = new QueryRunner();
- stu = qr.query(conn, sql, new BeanHandler<>(Student.class), idx);
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- try {
- //关闭链接,释放资源
- conn.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- return stu;
- }
Neste ponto, o preenchimento dos espaços reservados e a retirada do conjunto de resultados podem ser realizados com duas linhas de código.
detalhe:
① O método de consulta precisa passar 4 parâmetros:
Objeto de conexão
Instrução SQL
O objeto de classe de implementação da interface ResultSetHandler (o tipo do objeto convertido precisa ser: Student.class)
Parâmetros para preencher espaços reservados
② A interface ResultSetHandler é usada para processar conjuntos de resultados. Ela pode converter os conjuntos de resultados consultados em objetos Java.
Manipulador de feijão | Mapeie o conjunto de resultados em um objeto Java (como o objeto Student) |
Manipulador de BeanList | Mapeie o conjunto de resultados em uma coleção List (como: List<Student > ) |
Manipulador de Mapas | Mapeie o conjunto de resultados em um objeto de coleção Map (ou seja: Mapa<String,Object> chave: nome do atributo; valor do atributo) |
Manipulador de Lista de Mapas | Mapeie o conjunto de resultados em uma coleção MapList (ou seja: List <Map<<String,Object> >) |
③ O parâmetro a ser preenchido no espaço reservado é um parâmetro variável, portanto, qualquer número de parâmetros pode ser passado para atender às diferentes necessidades dos usuários.
④ A classe de objeto convertida (classe Student) deve ter um construtor sem parâmetros, caso contrário o programa reportará um erro.
razão:A camada inferior encontra esta classe através de Student.class e, em seguida, através demecanismo de reflexãoEncontre o construtor sem parâmetros desta classe e crie seu objeto.
⑤ O nome do atributo na classe deve ser exatamente igual ao nome do campo na tabela do banco de dados.
Porque após a criação do objeto, ao atribuir valores às propriedades do objeto com base no conjunto de resultados, a pesquisa e a atribuição são realizadas com base no nome.
O que é MVC?
Após a solicitação entrar na aplicação JavaWeb, o Controlador recebe a solicitação, realiza o processamento da lógica de negócio e, por fim, retorna o resultado ao usuário (Visualização + Modelo).
Nos primeiros anos, ao operar aplicações web, os usuários acessavam diretamente a camada de controle, e a camada de controle podia operar diretamente o banco de dados:
servlet--CRUD (adicionar, excluir, modificar)-->banco de dados
No código do servlet: processamento de solicitações, respostas, saltos de visualização, processamento JDBC, processamento de código de negócios e processamento de código lógico
Desvantagens:O programa está muito inchado e não propício à manutenção
solução: Não há nada que adicionar outra camada não resolva, se houver, adicione outra camada!
Modelo
visualizar
Controlador (Servlet)
Tomemos como exemplo o login de usuário e administrador:
Camada controladora:
- @WebServlet("/login")
- public class LoginServlet extends HttpServlet {
-
- private LoginService loginService = new LoginServiceImpl();
-
- /* 处理登录的业务逻辑*/
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- String username = req.getParameter("username");
- String password = req.getParameter("password");
- String type = req.getParameter("type");
- Object object = loginService.login(username,password,type);
- if(object != null){
- HttpSession session = req.getSession();
- switch (type){
- case "reader":
- Reader reader = (Reader) object;
- session.setAttribute("reader",reader);
- //跳转到用户的首页
- resp.sendRedirect("/book?page=1");
- break;
- case "admin":
- Admin admin = (Admin) object;
- session.setAttribute("admin",admin);
- //跳转到管理员的首页
- resp.sendRedirect("/admin?method=findAllBorrow&page=1");
- break;
- }
- }else{
- resp.sendRedirect("login.jsp");
- }
- }
-
- }
Camada de serviço:
- public interface LoginService {
- //利用多态,动态返回不同类型的对象
- public Object login(String username,String password,String type);
- }
- public class LoginServiceImpl implements LoginService {
-
- private ReaderRepository readerRepository = new ReaderRepositoryImpl();
- private AdminRepository adminRepository = new AdminRepositoryImpl();
-
- @Override
- public Object login(String username, String password,String type) {
- Object object = null;
- //业务逻辑处理:根据type的值,来选择调用不同的登录方法,去查找不同的表
- switch (type){
- case "reader":
- object = readerRepository.login(username,password);
- break;
- case "admin":
- object = adminRepository.login(username, password);
- break;
- }
- return object;
- }
- }
Camada Dao/Repositório:
- public interface AdminRepository {
- public Admin login(String username,String password);
- }
- public interface ReaderRepository {
- public Reader login(String username,String password);
- }
- public class AdminRepositoryImpl implements AdminRepository {
- //管理员的登录方法(和数据库交互)
- @Override
- public Admin login(String username, String password) {
- Connection connection = JDBCTools.getConnection();
- String sql = "select * from bookadmin where username = ? and password = ?";
- PreparedStatement statement = null;
- ResultSet resultSet = null;
- Admin admin = null;
- try {
- statement = connection.prepareStatement(sql);
- statement.setString(1,username);
- statement.setString(2,password);
- resultSet = statement.executeQuery();
- if(resultSet.next()){
- admin = new Admin(resultSet.getInt(1),resultSet.getString(2),resultSet.getString(3));
- }
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- JDBCTools.release(connection,statement,resultSet);
- }
- return admin;
- }
- }
- public class ReaderRepositoryImpl implements ReaderRepository {
- //用户的登录方法(和数据库交互)
- @Override
- public Reader login(String username, String password) {
- Connection connection = JDBCTools.getConnection();
- String sql = "select * from reader where username = ? and password = ?";
- PreparedStatement statement = null;
- ResultSet resultSet = null;
- Reader reader = null;
- try {
- statement = connection.prepareStatement(sql);
- statement.setString(1,username);
- statement.setString(2,password);
- resultSet = statement.executeQuery();
- if(resultSet.next()){
- reader = new Reader(resultSet.getInt(1),resultSet.getString(2),resultSet.getString(3),resultSet.getString(4),resultSet.getString(5),resultSet.getString(6),resultSet.getString(7));
- }
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- JDBCTools.release(connection,statement,resultSet);
- }
- return reader;
- }
- }