当前位置:网站首页>JDBC入门学习(三)之事务回滚功能的实现
JDBC入门学习(三)之事务回滚功能的实现
2022-06-23 03:55:00 【默主归沙】
- 事务(重点)
案例: 转账功能
//发送方减钱
int result = accountDao.update(sendAccount);
//完成一个功能后,后面的接收方操作无法完成,数据出现问题,如何处理
//接收方加钱
result = accountDao.update(recvAccount);
事务:将转账功能的多条SQL语句放入事务中,要么都成功,则提交;要么都失败,则回滚
事务如何加?在哪个层次加,为什么?
service层,如果只完成一个SQL语句,则回滚;都完成了则提交;例如
try{
//开启事务
//发送方减钱
int result = accountDao.update(sendAccount);
//异常
//接收方加钱
result = accountDao.update(recvAccount);
//提交事务
}catch(Exception e){
//回滚
}
问题1:出现异常后,无法进行回滚
原因:处理事务的连接对象和SQL操作的连接对象不是同一个
解决方案:
1.将事务处理的连接对象传入到dao层,共SQL操作使用–不推荐,容易造成接口污染
2.通过ThreadLocal来确保service和dao层操作同一对象–推荐
ThreadLocal的用法类似Map集合,通过键值对存储;
可以在service和dao层中操作同一个共享值,这个共享值就是连接对象
问题2:执行完一个SQL,关闭了连接对象;再次执行SQL会报错
解决方案:统一在提交或回滚事务时,才关闭连接对象
//==============DBUtils工具类==============
public class DBUtils {
private static Properties p = new Properties();
private static ThreadLocal<Connection> th = new ThreadLocal<>();
//静态代码块:只加载一次
static{
//反射对象调用getResourceAsStream
//从src目录下获取到db.properties的资源
try {
InputStream is = DBUtils.class.getResourceAsStream("/db.properties");
p.load(is);
Class.forName(p.getProperty("driver"));
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection(){
Connection conn = null;
try {
conn = th.get(); //从ThreadLocal中获取连接对象
if(conn==null){
conn = DriverManager.getConnection(p.getProperty("url"), p.getProperty("username"), p.getProperty("password"));
th.set(conn); //将连接对象存储到ThreadLocal
}
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static void begin() throws SQLException {
Connection conn = getConnection();
conn.setAutoCommit(false); //开启事务
}
public static void commit() throws SQLException {
Connection conn = getConnection();
conn.commit();
closeAll(conn); //关闭资源
}
public static void rollback(){
Connection conn = getConnection();
try {
conn.rollback();
closeAll(conn); //关闭资源
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void closeAll(AutoCloseable...cs){
for(AutoCloseable c : cs){
if(c!=null){
try {
c.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
th.remove(); //移除th对象
}
}
//==========转账业务层代码=========
try {
//开启事务
DBUtils.begin(); //开启事务
sendAccount.setMoney(sendAccount.getMoney()-money);
int result = accountDao.update(sendAccount);
System.out.println("发送方修改:"+result);
//int i=1/0; //模拟异常
recvAccount.setMoney(recvAccount.getMoney()+money);
result = accountDao.update(recvAccount);
System.out.println("发送方修改:"+result);
DBUtils.commit(); //提交事务
}catch (Exception e){
System.out.println("事务回滚了");
DBUtils.rollback(); //事务回滚
return "转账失败~~!";
}
return "转账成功~~!";
- 三层架构
什么是三层架构?
与数据库操作的功能,划分了三个层次,分别是:表示层(main),业务层,数据访问层
表示层:
将准备的参数传给业务层,并接收业务层反馈(main)
业务层:(接口与实现类)
业务逻辑处理,调用dao层方法,并接收返回结果
数据访问层:(接口与实现类)
与数据库的交互操作

//完整的三层架构的操作步骤:
//1.创建实体类
//2.DBUtils的工具类
//3.dao层的接口与实现类
//4.service层的接口与实现类
//5.通过测试类进行测试,具体结果反馈,返回到测试类中
//注意:此处加了接口与实现类,方便后续的扩展与维护
public class UserTest {
public static void main(String[] args) {
//面向接口编程:
UserService userService = new UserServiceImpl();
List<User> list = userService.selectAll(); //查询所有
}
}
- DaoUtils(重点)
dao层的jdbc操作有太多的冗余代码
DaoUtils就是针对dao层代码进行封装,这样可以进行增删改查的复用
//----------DaoUtils封装---------
//对dao层的增删改查的jdbc进行优化
public class DaoUtils {
//增删改的封装
//返回值--int(与数据库返回相关)
//参数:增删改中编号的数据抽取到参数-sql,传入数据
public static int commonUpdate(String sql,Object... objs) {
Connection conn = null;
PreparedStatement prst = null;
try {
conn = DBUtils.getConnection();
prst = conn.prepareStatement(sql);
//有多少个参数,就有多少个Object
for (int i = 0; i < objs.length; i++) {
prst.setObject(i + 1, objs[i]);
}
return prst.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtils.closeAll(prst, conn);
}
return 0;
}
//DQL的封装:
//返回值:集合的泛型
//参数:sql, 反射对象,所有参数
public static <T> List<T> commonQuery(String sql,Class<T> clazz,Object...objs){
Connection conn = null;
PreparedStatement prst = null;
ResultSet rs = null;
List<T> list = new ArrayList<>();
try {
conn = DBUtils.getConnection();
prst = conn.prepareStatement(sql);
for(int i=0;i<objs.length;i++){
prst.setObject(i+1,objs[i]);
}
rs = prst.executeQuery();
Field[] fields = clazz.getDeclaredFields();
while(rs.next()){
//如何将数据进行ORM
//rs.getObject传字段名(未知)-->已知属性名,只要属性名和字段名匹配,则可以注入值
//获取属性名的数组:
//循环遍历取出属性名,并通过属性名充当字段,得到字段内容
T t = clazz.newInstance();
for(Field f:fields){
//获取field对象
Object value = rs.getObject(f.getName()); //字段名一定要与属性名一致
f.setAccessible(true); //开启权限
f.set(t,value); //赋值
}
list.add(t); //将实体对象存入List
}
} catch (Exception e) {
e.printStackTrace();
}finally {
DBUtils.closeAll(rs,prst,conn);
}
return list;
}
}
//----------PersonDaoImpl---------
//dao层--数据访问层(用于做jdbc操作)
public class PersonDaoImpl {
public int insert(Person p) {
String sql = "insert into person(name,age,bornDate,email,address) values(?,?,?,?,?)";
return DaoUtils.commonUpdate(sql,p.getName(),p.getAge(),p.getBornDate(),p.getEmail(),p.getAddress());
}
public int update(Person p) {
String sql = "update person set name=?,age=? where id=?";
return DaoUtils.commonUpdate(sql,p.getName(),p.getAge(),p.getId());
}
public int delete(int id) {
String sql = "delete from person where id=?";
return DaoUtils.commonUpdate(sql,id);
}
public Person selectById(int id) {
String sql = "select * from person where id=?";
List<Person> list = DaoUtils.commonQuery(sql,Person.class,id);
if(list.size()>0){
return list.get(0);
}
return null;
}
public List<Person> selectAll() {
String sql = "select * from person";
return DaoUtils.commonQuery(sql,Person.class);
}
}
边栏推荐
猜你喜欢

APP自动化测试-Appium进阶

UI automation positioning edge -xpath actual combat

insert into... Where not exists insert to avoid repeated use

PRCS-1016 : Failed to resolve Single Client Access Name

VMware network connection error unit network service not found

Introduction and use of precise ephemeris

Baidu PaddlePaddle's "universal gravitation" first stop in 2022 landed in Suzhou, comprehensively launching the SME empowerment plan

开源生态|超实用开源License基础知识扫盲帖(下)

STP summary

servlet自学笔记
随机推荐
VMware network connection error unit network service not found
vmware网络连接出错Unit network.service not found
Strong push, quick start to software testing
TIOBE 编程语言排行榜是编程语言流行趋势的一个指标
[MAC] there is no source option in security and privacy
Image noise reduction denoise AI
Raspberry pie network remote access
关于DOS/DDOS攻击和防御
Laravel8 implementation of picture verification code
Swiftui 2.0 course notes Chapter 4
Fund performance evaluation
【C语言】关键字
新晋职场人的 技术进击?之旅
【微服务|Nacos】Nacos版本相关问题一览
Cookie session explanation
开源生态|超实用开源License基础知识扫盲帖(下)
One or more lines of text overflow, ellipsis instead
大環境不好難找工作?三面阿裏,幸好做足了准備,已拿offer
The propeller framework v2.3 releases the highly reusable operator library Phi! Restructure development paradigm to reduce cost and increase efficiency
李宏毅《机器学习》丨5. Tips for neural network design(神经网络设计技巧)