写点什么

Java 基础 27~ 使用 JDBC+ 连接池,这篇文章可以满足你 80% 日常工作

用户头像
极客good
关注
发布于: 刚刚

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<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


  1. 创建 ComboPooledDataSource 对象

  2. 配置连接池对象

  3. 调用 getConnection 获得连接

  4. 执行 CRUD 操作

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


配置文件


src 下添加:c3p0-config.xml


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


<c3p0-config>


<default-config>


<property name="driverClass">com.mysql.jdbc.Driver</property>


<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>


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


}


}


}


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


问题:


  1. 表的名称不同

  2. 返回值类型不同


分析:


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

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

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


/**


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


*/


public static <T> List<T> query(Class<T> clazz, String sql, Object... args) throws Exception {


List<T> 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]);


}


//查询每一行


ResultSet resultSet = preparedStatement.executeQuery();


while(resultSe


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


t.next()){


//创建对象


T obj = clazz.newInstance();


//获得所有属性


Field[] fields = clazz.getDeclaredFields();


//遍历属性


for(Field field : fields){


String name = field.getName();


//获得属性对应列的值


Object value = resultSet.getObject(name);


field.setAccessible(true);


//给对象属性赋值


field.set(obj,cast(field.getType(),value));


}


list.add(obj);


}


return list;


}

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
Java基础27~使用JDBC+连接池,这篇文章可以满足你80%日常工作