2、事务及JDBCUtils最终版
回顾事务概念:将多个操作步骤归为同一个原子操作,要么同时成功,要么同时失败
开启事务
执行操作
结束事务:commit rollback
通常需要添加在Service层,Service层的所有功能方法都应该配套事务
2.1、事务基本操作与问题解决
开启事务:Connection对象.setAutoCommit(false)
结束事务:
提交:Connection对象.commit();
回滚:Connection对象.rollback();
2.1.1、存在问题
操作事务和操作数据库数据的数据库连接不是同一个,或导致事务回滚不会影响数据库内容
2.1.2、解决方案:ThreadLocal
思路: 放入线程的存储空间中,Service和DAO不再自行创建conn,如有需要,直接从线程存储空间中取出
实现:
1.确保工具类只会创建一个conn对象
2.使用ThreadLocal将工具类创建的conn对象放入存储空间
ThreadLocal:可以操作线程存储空间的工具,可以对空间的数据进行添加、获取、删除
添加:ThreadLocal对象.set(数据)
获取:ThreadLocal对象.get()
删除:ThreadLocal对象.remove()
使用:
由于DAO和Service共用同一个conn,并且Service一定晚于DAO执行结束,所以为了确保Service的执行,DAO中不能关闭conn,该操作应由Service完成
2.2、JDBCUtils-最终版
package com.bz.util; import java.io.InputStream; import java.sql.*; import java.util.Properties; /** * 工具类:方便方法调用,所有方法都应为静态方法 */ public class JDBCUtils { //提升集合的作用范围,确保getConnection方法中也能使用 private static Properties p=null; //创建操作线程存储空间的工具对象 private static ThreadLocal<Connection> tl=new ThreadLocal<>(); //把流对象的创建放入静态初始代码块,确保在工具类类加载时执行 static{ try( //通过类对象.getResourseAsStream()获取一个字节输入流对象 //当前配置文件在src之下 InputStream is=JDBCUtils.class.getResourceAsStream("/jdbc.properties"); ){ //创建用来接收的Properties集合 p=new Properties(); //调用方法加载配置文件的内容至集合中 p.load(is); //1. 加载驱动 Class.forName(p.getProperty("driverClassName")); }catch (ClassNotFoundException e) { System.out.println("驱动路径不正确"); } catch (Exception e){ e.printStackTrace(); } } /** * 获取Connection连接 * @return */ public static Connection getConnection(){ Connection conn =tl.get(); try { if (conn==null) {//这里如果线程存储空间里没有conn就创建conn并存入线程空间 //2. 获取连接 //连接的url String url = p.getProperty("url"); //用户名 String username = p.getProperty("username"); //密码 String pwd = p.getProperty("password"); conn = DriverManager.getConnection(url, username, pwd); //将新创建的conn放入线程的存储空间 tl.set(conn); } } catch (SQLException e) { System.out.println("获取连接失败"); } catch (Exception e) { System.out.println("未知异常"); e.printStackTrace(); } return conn; } /** * 关闭资源连接 非空判断:防止空指针 * @param rs * @param ps * @param conn */ public static void close(ResultSet rs, PreparedStatement ps,Connection conn){ if (rs!=null){ try { rs.close(); } catch (SQLException e) { System.out.println("关闭rs失败"); } } if (ps!=null){ try { ps.close(); } catch (SQLException e) { System.out.println("关闭ps失败"); } } if (conn!=null){ try { conn.close(); } catch (SQLException e) { System.out.println("关闭conn失败"); } } } }
3、JUnit测试框架
作用:DAO层和Service层中的方法通常需要经过测试,JUnit可以通过@Test注解完成执行测试,大大减少测试成本
3.1、使用步骤
1.导入jar包:
hamcrest-core-1.3.jar
junit-4.12.jar
2.创建测试类
命名:被测试的类/接口+Test
包:须放在test包下
3.使用
@Test注解必须写在方法上方
方法必须为公开、非静态、无参、无返回值的最普通的普通方法
一个测试方法中只能测试一个方法
通常情况下,测试方法名应与被测试方法一致,目的更为清晰
3.2、使用示例
package com.bz.test; import com.bz.dao.AccountDao; import com.bz.dao.impl.AccountDaoImpl; import com.bz.entity.Account; import org.junit.Test; public class AccountDaoImplTest { //创建被测试的对象 AccountDao ad=new AccountDaoImpl(); @Test public void selectAccountByName(){ Account a = ad.selectAccountByName("张三"); System.out.println(a); } @Test public void updateAccountByName(){ int n = ad.updateAccountByName("张三", 100); System.out.println(n); } }
4、JDBC项目开发步骤总结
首先要根据要求来建库建表(数据库的内部操作)
1.导入jar包:
hamcrest-core-1.3.jar
junit-4.12.jar
mysql-connector-java-8.0.23.jar
2.添加工具类(JDBCUtils最终版)
3.在src下添加工具类所需的jdbc.properties
4.书写实体类
5.搭建DAO
必须测试
6.搭建Service
最好也进行测试
7.书写view(不需要过多关注,实际开发中该层对接的应该是浏览器页面)
项目结构图示:
高效掌握JDBC的分享到此结束,希望对大家有所帮助,如有疑问欢迎大家交流指正。