Java基础27~使用JDBC+连接池,血与泪的总结

本文介绍了Java使用JDBC进行数据库操作的基本步骤,包括Statement和PreparedStatement接口的使用,批处理的概念及实现,以及数据库连接池的重要性和常见连接池如C3p0的配置。此外,还展示了如何使用JDBC结合连接池和反射实现简单的ORM框架。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

| boolean first() | 移动第一行,返回是否有数据 |

| boolean last() | 移动到最后一行,返回是否有数据 |

| String getString(“列名” 或 列索引) | 获得某一列的字符串值 |

| int getInt(“列名” 或 列索引) | 获得某一列的整数值 |

JDBC的操作步骤


  1. 下载mysql驱动包,导入到项目中

  2. 导入驱动包中的Driver类到内存 Class.forName(“包名+类名”);

  3. 通过DriverManager获得Connection对象

  4. 通过Connection对象获得Statement对象

  5. Statement对象执行增删改查命令

  6. 如果是查询,获得ResultSet对象

  7. 遍历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

《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享

  • 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();

}

}

}

PreparedStatement接口


Statement的子接口

优点:对SQL语句进行了预编译,数据库可以直接执行,更加高效和安全。

创建方法:

Connection对象.prepareStatement(“SQL语句”);

常用方法:

| 方法名 | 说明 |

| — | — |

| setXXX(占位符位置,值) | 给占位符赋值,如:setInt、setString、setFloat… |

| ResultSet executeQuery() | 执行查询 |

| int executeUpdate() | 执行增删改 |

批处理


当需要操作大量数据时,默认情况下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 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 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

  1. 创建ComboPooledDataSource对象

  2. 配置连接池对象

  3. 调用getConnection获得连接

  4. 执行CRUD操作

  5. 关闭连接,让连接回到池中

配置文件

src下添加:c3p0-config.xml

<?xml version="1.0" encoding="UTF-8"?>

com.mysql.jdbc.Driver

jdbc:mysql://localhost:3306/mydb

root

123456

10

30

100

10

200

案例:使用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();

}

}

}

查询操作,查询不同的表,返回不同类型的集合

问题:

  1. 表的名称不同

  2. 返回值类型不同

分析:

  1. 使用泛型方法,通过T来代替返回值的类型,类型由Class参数传入

  2. 通过反射机制创建对象,给对象的属性赋值

  3. 前提是实体类的属性名和表的字段名一致

/**

  • 数据库查询,获得对象集合

*/

public static List query(Class clazz, String sql, Object… args) throws Exception {

List list = new ArrayList<>();

//获得连接

Connection connection = dataSource.getConnection();

//获得命令对象

PreparedStatement preparedStatement = connection.prepareStatement(sql);

//设置占位符参数值

for(int i = 0;i < args.length;i++){

preparedStatement.setObject(i + 1,args[i]);

}

//查询每一行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值