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
- Baixe o pacote do driver mysql e importe-o para o projeto
- Importe a classe Driver do pacote de driver para a memória Class.forName ("nome do pacote + nome da classe");
- Obtenha o objeto Connection através do DriverManager
- Obtenha o objeto Statement através do objeto Connection
- O objeto de instrução executa comandos de adição, exclusão, modificação e consulta
- Se for uma consulta, obtenha o objeto ResultSet
- 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语句,执行效率比较低。
批处理:将多条语句打包,一起编译,一起发送给数据库,数据库一起执行。
实现方法:
- 需要关闭连接对象的自动提交
- 创建PreparedStatement对象
- 设置SQL语句和占位符
- 调用PreparedStatement的addBatch方法,添加SQL命令到批处理中
- 调用executeBatch()执行批处理
- 调用连接对象的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连接池的使用
步骤
- 从官网下载jar包 http://www.mchange.com/projects/c3p0/index.html
c3p0-0.9.5.2.jar
mchange-commons-java-0.2.11.jar - 创建ComboPooledDataSource对象
- 配置连接池对象
- 调用getConnection获得连接
- 执行CRUD操作
- 关闭连接,让连接回到池中
配置文件
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对象的操作,完成对数据库的增删改查,下面模拟其中的保存操作。
需求:
- 通用的save方法
- 参数是Java对象
- 可以向任何表插入一条数据
问题:
- 不同表的save方法,参数类型不一样
- insert语句是不一样的
分析:
- 将参数设置为Object
- 将实体类名、属性名设置成和表名、字段名一致
- 通过反射读取对象的类名,属性名,动态拼接SQL语句
- 调用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方法,查询不同的表,返回不同类型的集合
问题:
- 表的名称不同
- 返回值类型不同
分析:
- 给findAll传Class参数,通过getSimpleName获得类名,就是表名
- 使用泛型方法,通过T来代替类型,具体类型由Class参数传入
public static <T> List<T> findAll(String sql,Class clazz){
}
- 使用反射实现SQL拼接
- 从结果集中读取数据后,动态创建对象,调用所有的setXXX方法,给对象赋值
大家如果需要学习其他Java知识点,戳这里 超详细的Java知识点汇总