前言在Java开发中,不可避免地要使用 数据库来存储和管理数据尤其是在JavaWeb应用程序中,往往会有很多用户同时连接和访问数据库,对数据库连接的管理将直接影响到程序的性能和用户的体验使用数据库连接池能够加快数据库连接的速度,提高服务器程序的性能,降低系统资源的消耗,是对数据库连接的一种较为有效的管理手段。
文章介绍了数据库连接池的原理与使用方法JDBCjdbc是一个组件,能都被多种数据库访问,由java语言编写的类和接口组成为什么要学习JDBC规范JDBC是java连接数据库的一个标准,由数据库各个厂商来完成接口的实现
读者福利:转发+关注 私信【学习笔记】获取小编整理好的Java知识点200页学习笔记JDBC执行规范注册驱动,加载JDBC驱动获取连接对象获取预编译语句对象preparedStatement执行SQL语句。
释放资源1.Class.forName(com.mysql.jdbc.Driver); 2.Connection connection =DriverManager.getConnection("jdbc:mysql://localhost:3306/数据库名称"
,"root(用户名)","密码") //如果是本机端口为3306,可以省略 Connection connection =DriverManager.getConnection("jdbc:mysql:///数据库名称"
,"root(用户名)","密码") // ? 使用的是占位符来进行拼接3.String sql = "update t_student set name=? ,age=?,email=? where id=?"
//获取预编译对象,传入sql4.PreparedStatement statement = connection.prepareStatement(sql); //执行 statement.executeUpdate();
//释放资源 statement.close(); connection.close();在使用PreparedStatement 调用executeUpdate()等操作时,最好不要传入sql语句Statement 和PreparedStatement的区别
PreparedStatement提供更好的性能(预编译)PreparedStatement更安全,可以防止SQL注入问题 ,使用 ?占位符,提前预编译到数据库中,语句结构固定下来DAO思想DAO(Data Acess Object ):数据访问对象 (面向对象的数据库接口),自己定义接口与实现实现类的设计思想,用于封装减少重复代码,DAO其实就是一个组件(可以重复使用)
定义DAO包使用倒置域名定义DAO包cn.k.dao: //定义dao包,用来定义类的接口dao包中接口的命名规范 IXxxDAOcn.k.dao.impl : //定义impl包,拿来装dao包中接口的实现类
impl包中的实现类命名规范 XXXDAOImplcn.k.domain: //定义domain包,用来放类的对象cn.k.util :工具包,用来放工具类cn.k.test: 放置测试类DAO查询操作
ResultSet接口 :通过执行DQL语句查询之后的结果对象ResultSet对象具有指向其当前数据行的光标.next()方法将光标移动到下一行,移到下一行时(上一行的数据会被覆盖)如果Result对象没有下一行时返回false,所以可以使用while循环进行迭代
例子:实体类package cn.k.domain; @DatapublicclassStudent{ privateLong id; private String name;
private Integer age; private String email; }定义接口publicinterfaceIStudentDAO { //操作数据库的增删改查方法//添加
voidinsert(Student student); //删除voiddeleteById(Long id); //修改voidupdate(Student student);
//查询Student selectById(Long id); //查询所有List selectAll(); } 定义实现类
publicclassStudentDAOImplimplementsIStudentDAO{ @Overridepublic Student selectById(Long id){ Student student =
new Student(); String sql = "select*from t_student where id=?"; Connection connection =
null; PreparedStatement statement = null; ResultSet resultSet = null; try {
//加载驱动 Class.forName("com.mysql.jdbc.Driver"); //获取连接对象 connection = DriverManager.getConnection(
"jdbc:mysql:///product", "root", "123"); //获取预编译对象 statement = connection.prepareStatement(sql);
//设置参数 statement.setLong(1, id); //发送 数据到数据库服务器 resultSet = statement.executeQuery();
//迭代结果集while (resultSet.next()) { long id1 = resultSet.getLong("id"); String name = resultSet.getString(
"name"); int age = resultSet.getInt("age"); String email = resultSet.getString(
"email"); student.setId(id1); student.setName(name); student.setAge(age); student.setEmail(email); } }
catch (Exception e) { e.printStackTrace(); } finally { //关闭资源if (statement !=
null) { try { statement.close(); } catch (SQLException e) { e.printStackTrace(); } }
if (connection != null) { try { connection.close(); }
catch (SQLException e) { e.printStackTrace(); } } }
return student; } }重构思想对代码进行优化,即重构,从代码量来讲更加简约,将相同构造的代码抽取出来,进行分类使用JDBC的规范来实现接口代码的重构1.对资源释放进行抽取; 2.对连接对象进行抽取 ; 3.对连接数据库的参数进行了抽取
扩展4.对DML操作进行模板化实现,达到代码的复用性目的5.对DQL操作进行模板化实现,达到代码的复用性目的对teacher类定义增删改查方法查询数据库(重构)- 定义工具类Util包JDBCUtil (封装关闭异常方法,加载数据库配置文件properties)
package cn.kent.util; import java.sql.*; import java.util.Properties; publicfinalclassJDBCUtil{ private
JDBCUtil(){} privatestatic Properties properties=new Properties(); //静态代码块static { try
{ //加载配置文件 properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream(
"db.properties")); //加载驱动,只加载一次 Class.forName("com.mysql.jdbc.Driver"); }
catch (Exception e) { e.printStackTrace(); } } publicstatic Connection
getConnection(){ //获取连接对象 Connection connection =null; try { connection= DriverManager.getConnection( properties.getProperty(
"url"), properties.getProperty("username"), properties.getProperty(
"password") ); } catch (SQLException e) { e.printStackTrace(); }
return connection; } //释放资源publicstaticvoidrelease(PreparedStatement statement, Connection connection, ResultSet resultSet)
{ if (statement != null) { try { statement.close(); }
catch (SQLException e) { e.printStackTrace(); } }
if (connection != null) { try { connection.close(); }
catch (SQLException e) { e.printStackTrace(); } }
if (resultSet != null) { try { resultSet.close(); }
catch (SQLException e) { e.printStackTrace(); } } }
//释放资源,重载关闭两个资源publicstaticvoidrelease(PreparedStatement statement, Connection connection){ release(statement,connection,
null); } }DQLUtil类编写工具方法executeUpdate,executeQuery等publicabstractclassDQLUtil{ //编写DML方法,传入SQL语句,与可变参数
publicstatic void executeUpdate(String sql,Object...objects){ Connection connection=null; PreparedStatement statement=
null; try { //获取连接对象,调用JDBCUtil中的getConnection()获取到连接对象 connection=JDBCUtil.getConnection();
//获取语句对象 statement=connection.prepareStatement(sql); //设置参数for (int i = 0; i < objects.length; i++) { statement.setObject(i+
1,objects[i]); } //执行sql的DML方法 statement.executeUpdate(); }
catch (Exception e) { e.printStackTrace(); }finally { //释放资源 JDBCUtil.release(statement,connection); } }
//查询方法 ,定义泛型 ,提供字节码 ,自定义接口ResultSeHandlerpublicstatic List executeQuery(String sql, ResultSeHandler handler,
Class als, Object...objects) { List list =new ArrayList<>(); Connection connection=
null; PreparedStatement statement=null; ResultSet resultSet=null; try {
//获取连接对象 connection=JDBCUtil.getConnection(); //获取语句对象 statement=connection.prepareStatement(sql);
//设置参数for (int i = 0; i < objects.length; i++) { statement.setObject(i+1,objects[i]); }
//执行sql resultSet =statement.executeQuery(); //需要进行返回值,调用接口实现中的方法List list1 = handler.handleResultSet(resultSet, als);
return list1; } catch (Exception e) { e.printStackTrace(); }finally { JDBCUtil.release(statement,connection,resultSet); }
returnlist; } }定义ResultSeHandler 接口publicinterfaceResultSeHandler { List handleResultSet(ResultSet resultSet,
Class acl); }ResultSetHandlerImpl实现类publicclassResultSetHandlerImpl implementsResultSeHandler
{ @Overridepublic List handleResultSet(ResultSet resultSet, Class acl){ List list =
new ArrayList<>(); try { BeanInfo beanInfo = Introspector.getBeanInfo(acl, Object
.class); PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
while (resultSet.next()) { T t =acl.newInstance(); for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
//获取对象中的属性 String name = propertyDescriptor.getName(); //获取数据库中的列名
Object value = resultSet.getObject(name); // System.out.println(value);
//获取set方法 Method writeMethod = propertyDescriptor.getWriteMethod();
//执行 writeMethod.invoke(t,value); } //装进集合 list.add(t); } }
catch (Exception e) { e.printStackTrace(); } return list; } }
- domain包定义Teacher类@DatapublicclassTeacher{ privateint id; private String name; private Integer age;
private String email; }- dao包定义接口ITeacherDAOpublicinterfaceITeacherDAO { //添加voidinsert(Teacher teacher
); //删除voiddelete(int id); //改voidupdate(Teacher teacher); //查询指定idTeacher select(int id)
; //查询所有List selectAll(); }impl包定义TeacherDAOImpl实现类publicclassTeacherDAOImplimplementsITeacherDAO
{ //插入@Overridepublicvoidinsert(Teacher teacher){ String sql = "insert into t_teacher (name,age,email) values(?,?,?)"
; DQLUtil.executeUpdate(sql,teacher.getName(),teacher.getAge(),teacher.getEmail()); }
//删除@Overridepublicvoiddelete(int id){ String sql ="delete from t_teacher where id =?"; DQLUtil.executeUpdate(sql,id); }
//更新@Overridepublicvoidupdate(Teacher teacher){ String sql ="update t_teacher set name=?,age=?,email=? where id=?"
; DQLUtil.executeUpdate(sql,teacher.getName(),teacher.getAge(),teacher.getEmail(),teacher.getId()); }
//查询 DQL@Overridepublic Teacher select(int id){ String sql = "select * from t_teacher where id=?"
; List list = DQLUtil.executeQuery(sql, new ResultSetHandlerImpl(), Teacher.class, id
); if (list!=null &&list.size() >0){ return list.get(0); } return
null; } //查询整个集合@Overridepublic List selectAll(){ String sql = "select*from t_teacher"
; List list1 = DQLUtil.executeQuery(sql, new ResultSetHandlerImpl(), Teacher.class);
return list1; } }- test包测试类publicclassTeacherDAOImplTest { privatestatic ITeacherDAO teacherDAO =
new TeacherDAOImpl(); //插入 @Test publicvoidinsert() { Teacher teacher = new Teacher(); teacher.setName(
"月月"); teacher.setAge(12); teacher.setEmail("我爱小轩"); teacherDAO.insert(teacher); }
//删除 @Test publicvoiddelete() { teacherDAO.delete(5); } //更新 @Test public
voidupdate() { Teacher teacher =new Teacher(); teacher.setName("臭猪"); teacher.setAge(
18); teacher.setEmail("fewgw"); teacher.setId(6); teacherDAO.update(teacher); }
//查询指定id @Test publicvoidselect() { Teacher select = teacherDAO.select(1); System.
out.println(select); } //查询集合 @Test publicvoidselectAll() { List list = teacherDAO.selectAll(); System.
out.println(list); } }JDBC事务操作事务(Transaction ,简称tx)让多个操作,捆绑在一起,多个操作中有一个失败,那么整个操作失败在数据库中,事务是指一组逻辑操作单元,使数据从一种状态换成另外一种状态,保证了操作要么同时成功,要么同时失败
事务的ACID属性原子性:指事务是一个不可分割的工作单位一致性:包装数据的完整性,事务必须使数据库从一个一致性状态变换到另外一个状态隔离性:指一个事务的执行不能被其他事务干扰持久性:一旦一个事务被提交,它的数据库中数据的改变是永久性的
对应方法只要事务开启了手动执行, 连接要么提交,要么回滚 不能省略连接池javax.sql.DataSource 接口用来存放多个连接对象,避免了资源浪费基本四要素:driverClassName,url,username,password
其他属性:对连接对象被限制的配置初始化连接最多连接数最少连接数最长等待时间最长超过时间常见的DataSource实现DBCP:Spring框架推荐C3P0:Hibernate框架(基本不用了)druid :阿里巴巴连接池
使用DBCP连接池DBCP与druid步骤基本一致基本写法首先导入相关数据池的jar包//DBCP数据库连接池 ,改造前publicclassDBCPDemo { publicstaticvoid
main(String[] args) throws SQLException { DataSource dataSource=setupDataSource(); Connection connection=dataSource.getConnection(); System.
out.println("connection = " + connection); } publicstatic DataSource setupDataSource() { BasicDataSource ds =
new BasicDataSource(); ds.setDriverClassName("com.mysql.jdbc.Driver"); ds.setUsername(
"root"); ds.setPassword("123"); ds.setUrl("jdbc:mysql:///product"); return ds; } }
但是这样去使用连接池,上述代码就会产生了硬编码,我们应该对其进行优化,即主流写法首先使用DBCP连接池时,对应的数据库信息应该从properties配置文件中读取,使用连接池首先需要创建DataSource对象,其中DBCP已经提供创建该对象的工厂方法
BasicDataSourceFactory.createDataSource(Properties properties),并且可以传入properties对象并读取该配置文件的内容,那么步骤就简化很多了,读者福利:转发+关注 私信【学习笔记】获取小编整理好的Java知识点200页学习笔记。
创建db.properties //注意名字是有指定写法的,不能随意修改 driverClassName=com.mysql.jdbc.Driver username=root password=123 url=jdbc:mysql:///product
创建工具类 DBCPUtilpublicfinalclassDBCPUtil{ privateDBCPUtil(){ } privatestatic DataSource ds =
null; //使用静态代码块,加载配置文件资源static { try { InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(
"db.properties"); Properties properties = new Properties(); //加载进properties内存中
properties.load(inputStream); //创建datasource对象,并传入properties对象 ds = BasicDataSourceFactory.createDataSource(properties); }
catch (Exception e) { e.printStackTrace(); } } //写一个工具方法 ,直接调用publicstatic
DataSource getDataSource(){ return ds; } //为了更简便 ,直接把连接对象步骤写进该方法publicstatic Connection
getConnection(){ try { return ds.getConnection(); } catch (SQLException e) { e.printStackTrace(); }
returnnull; } }测试类publicstaticvoidmain(String[] args) throws SQLException { //直接使用工具类,调用即可,成功连接到数据库
Connection connection =DBCPUtil.getConnection(); System.out.println("connection = "
+ connection); }原文链接:https://blog.csdn.net/kentlhxy/article/details/114627641
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。