Java Básico 27 ~ Use JDBC + pool de conexão + reflexão para escrever uma estrutura ORM simples

Como você que ama programar!
Aprenda cursos práticos SpringBoot https://edu.csdn.net/course/detail/31433
Aprenda cursos introdutórios SpringCloud https://edu.csdn.net/course/detail/31451


Prefácio

O desenvolvimento do projeto é inseparável do banco de dados JDBC é uma tecnologia que deve ser dominada para o desenvolvimento de banco de dados Java.

Visão geral do JDBC

A função de JDBC (Java Database Connectivity) é conectar-se ao banco de dados e realizar operações de adição, exclusão e modificação nos dados da tabela.

API JDBC 的

Sob o pacote java.sql

Nome da classe Descrição
DriverManager Classe de gerenciador de driver, gerenciar driver de banco de dados, obter conexão de banco de dados
Conexão Classe de conexão, conecte-se ao banco de dados
Declaração Interface de comando, envia comandos SQL para o banco de dados
Declaração preparada Interface de comando pré-compilada, subinterface da interface de comando
ResultSet Conjunto de resultados, salve os dados da consulta

Classe DriverManager

Usado para gerenciar a unidade e obter o objeto de conexão:

  • Conexão getConnection (string de URL)
  • Conexão getConnection (string de URL, número da conta, senha)

Escrita de string de URL:

jdbc:mysql://数据库服务器地址:3306/数据库名?参数=值&参数=值

Parâmetros de URL:

nome do parâmetro Descrição
do utilizador número da conta
senha senha
useSSL Se deve criptografar a transmissão verdadeiro / falso
useUnicode Se deve usar caracteres Unicode verdadeiro / falso
characterEncoding Especifique o tipo de codificação
serverTimezone Fuso horário

Interface de conexão

Realizar a comunicação com o banco de dados através do protocolo TCP / IP e realizar a conexão
Métodos comuns:

Nome do método Descrição
createStatement () Criar objeto de declaração
prepareStatement (String sql) Criar objeto PreparedStatement
setAutocommit () Defina se deseja enviar automaticamente
beginTransaction () Iniciar transação
commit () Confirmar transação
rollback () Transação de reversão
Fechar() Feche a conexão

Interface de declaração

Usado para enviar comandos SQL para o banco de dados
Métodos comuns:

Nome do método Descrição
ResultSet executeQuery (instrução SQL) Executar consulta
int executeUpdate (instrução SQL) Executar instruções de adição, exclusão e modificação
Fechar() Fechar comando

Interface ResultSet

Usado para consultar dados
Métodos comuns:

Nome do método Descrição
próximo booleano () Mova para a próxima linha, retorne para o final
primeiro booleano () Mova a primeira linha e retorne se há dados
último booleano () Vá para a última linha, retorne se há dados
String getString ("nome da coluna" ou índice da coluna) Obtenha o valor da string de uma coluna
int getInt ("nome da coluna" ou índice da coluna) Obtenha o valor inteiro de uma coluna

Etapas de operação JDBC

  1. Baixe o pacote do driver mysql e importe-o para o projeto
  2. Importe a classe Driver do pacote de driver para a memória Class.forName ("nome do pacote + nome da classe");
  3. Obtenha o objeto Connection através do DriverManager
  4. Obtenha o objeto Statement através do objeto Connection
  5. O objeto de instrução executa comandos de adição, exclusão, modificação e consulta
  6. Se for uma consulta, obtenha o objeto ResultSet
  7. Percorra os dados no objeto ResultSet
/**
 * 测试查询功能
 */
public class TestQuery {

	public static final String URL = "jdbc:mysql://localhost:3306/mydb";
	
	static{
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	@Test
	public void testJDBC(){
		try (Connection conn = DriverManager.getConnection(URL,"root","123456")){
			Statement statement = conn.createStatement();
			String sql = "insert into students(stu_name,stu_age,stu_gender,stu_class_id) values(‘张三’,20,‘男’,1)";
			int rows = statement.executeUpdate(sql);
			if(rows > 0){
				System.out.println("执行成功");
			}else{
				System.out.println("执行失败");
			}
			statement.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	@Test
	public void testQuery(){
		try(Connection conn = DriverManager.getConnection(URL,"root","123456")){
			Statement st = conn.createStatement();
			String sql = "select * from students";
			//执行查询操作,返回结果集
			ResultSet rs = st.executeQuery(sql);
			//循环访问每一行
			while(rs.next()){
				//访问每一列
				System.out.println("编号:"+rs.getInt("stu_id"));
				System.out.println("姓名:"+rs.getString("stu_name"));
				System.out.println("年龄:"+rs.getInt("stu_age"));
				System.out.println("性别:"+rs.getString("stu_gender"));
				System.out.println("班级:"+rs.getInt("stu_class_id"));
			}
			rs.close();
		}catch(SQLException ex){
			ex.printStackTrace();
		}
	}
}

Interface PreparedStatement


Vantagens da subinterface de instruções: As instruções SQL são pré-compiladas e o banco de dados pode ser executado diretamente, o que é mais eficiente e seguro.
Método de criação:

Connection对象.prepareStatement("SQL语句");

Métodos comuns:

Nome do método Descrição
setXXX (posição do marcador, valor) Atribua valores a marcadores de posição, como: setInt, setString, setFloat ...
ResultSet executeQuery () Executar consulta
int executeUpdate () Execute adições, exclusões e modificações

Processamento em lote

当需要操作大量数据时,默认情况下JDBC会单独编译和发送每一条SQL语句,执行效率比较低。
批处理:将多条语句打包,一起编译,一起发送给数据库,数据库一起执行。
实现方法:

  1. 需要关闭连接对象的自动提交
  2. 创建PreparedStatement对象
  3. 设置SQL语句和占位符
  4. 调用PreparedStatement的addBatch方法,添加SQL命令到批处理中
  5. 调用executeBatch()执行批处理
  6. 调用连接对象的commit方法
/**
 * 测试批处理
 */
public class TestBatch {
	
	public static final String URL = "jdbc:mysql://localhost:3306/mydb?user=root&password=123456";
	
	static{
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	//添加多个学生的信息
	public void addStudents(List<Student> students){
		try(Connection conn = DriverManager.getConnection(URL)){
			//关闭自动提交
			conn.setAutoCommit(false);
			String sql = "insert into students(stu_name,stu_age,stu_gender,stu_class_id) values(?,?,?,?)";
			PreparedStatement ps = conn.prepareStatement(sql);
			for(Student stu : students){
				//添加一个学生的信息
				ps.setString(1, stu.getStu_name());
				ps.setInt(2,stu.getStu_age());
				ps.setString(3, stu.getStu_gender());
				ps.setInt(4, stu.getStu_class_id());
				//添加到批处理
				ps.addBatch();
			}
			//执行批处理
			ps.executeBatch();
			//数据库提交
			conn.commit();
		}catch(SQLException ex){
			ex.printStackTrace();
		}
	}
	
	@Test
	public void testBatch(){
		List<Student> students = Arrays.asList(new Student(1,"马八",20,"男",1),
				new Student(1,"马大八",30,"男",1),new Student(1,"马小八",10,"男",1));
		addStudents(students);
	}
}

数据库连接池

创建数据库连接对象需要消耗比较多时间和内存,连接池开辟一个池,在池中放置一定数量的连接对象,用户使用连接对象后,连接不会直接销毁,而是回到池中,做其它操作时可以直接利用,减少连接对象的创建次数,从而提高程序的性能。

常用连接池

  • C3p0
    开源的,成熟的,高并发第三方数据库连接池,文档资料完善,hibernate框架就使用了c3p0
  • dbcp
    由Apache开发的一个数据库连接池,在tomcat7版本之前都是使用dbcp作为数据库连接池。
  • Druid
    阿里巴巴的连接池。Druid能够提供强大的监控和扩展功能。
  • BoneCP
    其官方说该数据库连接池性能非常棒,不过现在已经不更新了,转到了HiKariCP上。
  • HiKariCP
    Hikari是日语光的意思,作者可能想以此来表达HiKariCP速度之快。比之前的BoneCP性能更加强大,它官方展示了一些性能对比的数据,通过数据可以看出HiKariCP完虐c3p0,dbcp,tomcat jdbc pool等其他数据库连接池。并且它的库文件差不多就130kb,非常轻巧。
  • Proxool
    早期的一些项目中使用的多一些,现在该数据库连接池源码已经有一阵子不更新了。

C3P0连接池的使用

步骤

  1. 从官网下载jar包 http://www.mchange.com/projects/c3p0/index.html
    c3p0-0.9.5.2.jar
    mchange-commons-java-0.2.11.jar
  2. 创建ComboPooledDataSource对象
  3. 配置连接池对象
  4. 调用getConnection获得连接
  5. 执行CRUD操作
  6. 关闭连接,让连接回到池中

配置文件
src下添加:c3p0-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
  <default-config>
  	<!-- 必填 -->
  	<!-- 驱动类 -->
  	<property name="driverClass">com.mysql.jdbc.Driver</property>
  	<!-- URL -->
  	<property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb</property>
  	<!-- 账号 -->
  	<property name="user">root</property>
  	<!-- 密码 -->
  	<property name="password">123456</property>
  	<!-- 可选 -->
  	<!-- 初始连接数 -->
    <property name="initialPoolSize">10</property>
    <!-- 最大闲置时间 -->
    <property name="maxIdleTime">30</property>
    <!-- 最大连接数 -->
    <property name="maxPoolSize">100</property>
    <!-- 最小连接数 -->
    <property name="minPoolSize">10</property>
    <!-- 最大SQL语句数 -->
    <property name="maxStatements">200</property>
  </default-config>
</c3p0-config>

案例:使用JDBC+连接池+反射编写基本的ORM框架

常见的ORM(对象关系映射)框架,如Hibernate、MyBatis能通过对Java对象的操作,完成对数据库的增删改查,下面模拟其中的保存操作。
需求:

  1. 通用的save方法
  2. 参数是Java对象
  3. 可以向任何表插入一条数据

问题:

  1. 不同表的save方法,参数类型不一样
  2. insert语句是不一样的

分析:

  1. 将参数设置为Object
  2. 将实体类名、属性名设置成和表名、字段名一致
  3. 通过反射读取对象的类名,属性名,动态拼接SQL语句
  4. 调用getXXX方法,将值设置到SQL语句中
/**
 * JDBC工具类
 */
public class JDBCUtils {

	//连接池对象
	private static ComboPooledDataSource dataSource = new ComboPooledDataSource();
	
	/**
	 * 保存任意对象的数据到表中
	 * @param obj
	 */
	public static void save(Object obj){
		//获得对象的类型对象
		Class clazz = obj.getClass();
		//获得类名
		String className = clazz.getSimpleName();
		StringBuilder stb = new StringBuilder("insert into ");
		stb.append(className+"(");
		//获得所有的属性
		Field[] fields = clazz.getDeclaredFields();
		//i = 1跳过第一列自动增长主键
		for(int i = 1;i < fields.length;i++){
			stb.append(fields[i].getName()+",");
		}
		//删除最后的,
		stb.deleteCharAt(stb.length() - 1);
		stb.append(") values (");
		//添加?
		for(int i = 1;i < fields.length;i++){
			stb.append("?,");
		}
		//删除最后的,
		stb.deleteCharAt(stb.length() - 1);
		stb.append(")");
		System.out.println("test sql--- "+stb.toString());
		//添加数据
		try(Connection conn = dataSource.getConnection()){
			PreparedStatement ps = conn.prepareStatement(stb.toString());
			//设置SQL语句中的参数
			for(int i = 1;i < fields.length;i++){
				String fname = fields[i].getName();
				String mname = "get" + fname.substring(0, 1).toUpperCase() + fname.substring(1);
				System.out.println("method:"+mname);
				//调用方法获得返回值,给SQL参数赋值
				Method m = clazz.getMethod(mname);
				ps.setObject(i, m.invoke(obj));
			}
			//执行SQL
			ps.executeUpdate();
			System.out.println("添加完成!!!");
		}catch(Exception ex){
			ex.printStackTrace();
		}
	}
}

结束

作业:定义findAll方法,查询不同的表,返回不同类型的集合
问题:

  1. 表的名称不同
  2. 返回值类型不同

分析:

  1. 给findAll传Class参数,通过getSimpleName获得类名,就是表名
  2. 使用泛型方法,通过T来代替类型,具体类型由Class参数传入
public static <T> List<T> findAll(String sql,Class clazz){

}
  1. 使用反射实现SQL拼接
  2. 从结果集中读取数据后,动态创建对象,调用所有的setXXX方法,给对象赋值

大家如果需要学习其他Java知识点,戳这里 超详细的Java知识点汇总

Acho que você gosta

Origin blog.csdn.net/u013343114/article/details/112983307
Recomendado
Clasificación