工具类
package com.qcby.utils;import com.alibaba.druid.pool.DruidDataSource;import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;/*** 事务的工具类*/
//事务是通过连接开启的,所以要保证是同一个连接
public class TxUtils {//连接池对象private static DruidDataSource ds = null;//使用ThreadLocal存储当前线程中的connection对象private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();//在静态代码块中创建数据库连接池static {try {//通过代码创建C3P0数据库连接池ds = new DruidDataSource();ds.setDriverClassName("com.mysql.jdbc.Driver");ds.setUrl("jdbc:mysql:///spring_db");ds.setUsername("root");ds.setPassword("root");}catch (Exception e) {throw new ExceptionInInitializerError(e);}}/*** @Method: getConnection* @Description: 丛数据源中获取数据库连接* @Anthor:* @return Connection* @throws SQLException* 保证是相同的连接*/public static Connection getConn() throws SQLException{//从当前线程中获取ConnectionConnection conn = threadLocal.get();if(conn == null){//从数据源中获取数据库连接conn = getDataSource().getConnection();//将conn绑定到当前线程threadLocal.set(conn);}return conn;}/*** @Method: startTransaction* @Description: 开启事务* @Anthor:**/public static void startTransaction(){try {Connection conn = threadLocal.get();if(conn == null) {conn = getConn();//把conn绑定到当前线程上threadLocal.set(conn);}//开启事务conn.setAutoCommit(false);} catch (SQLException e) {throw new RuntimeException(e);}}/*** @Method: rollback* @Description:回滚事务* @Anthor:*/public static void rollback(){try {//从当前线程中获取connectionConnection conn = threadLocal.get();if(conn != null){//回滚事务conn.rollback();}}catch (Exception e) {throw new RuntimeException(e);}}/*** @Method: commit* @Description:提交事务* @Anthor:*/public static void commit(){try {//从当前线程中获取connectionConnection conn = threadLocal.get();if(conn != null){//提交事务conn.commit();}}catch (Exception e) {throw new RuntimeException(e);}}/*** @Method: close* @Description:关闭数据库连接(注意,并不是真的关闭,而是把连接还给数据库连接池)* @Anthor:**/public static void close(){try {Connection conn = threadLocal.get();if(conn != null){conn.close();//解除当前线程上绑定conn,使得每次使用的数据库是一个threadLocal.remove();}} catch (SQLException e) {throw new RuntimeException(e);}}/*** @Method: getDataSource* @Description: 获取数据源* @Anthor:* @return DataSource*/public static DataSource getDataSource(){//从数据源中获取数据库连接return ds;}
}
持久层
package com.qcby.dao;import com.qcby.model.Account;
import com.qcby.utils.TxUtils;
import org.springframework.stereotype.Repository;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;@Repository
public class AccountDaoImpl implements AccountDao {public void save(Account account) {try {//创建连接Connection conn = TxUtils.getConn();//编写sql语句String sql = "update account set money = money - 10 where name = ? ";//预编译sql语句PreparedStatement statement = conn.prepareStatement(sql);//设置值statement.setString(1,account.getName());//执行操作statement.executeUpdate();//关闭资源statement.close();} catch (SQLException e) {e.printStackTrace();}}
}
业务层(service)
package com.qcby.service.impl;import com.qcby.dao.AccountDao;
import com.qcby.model.Account;
import com.qcby.service.AccountService;
import com.qcby.utils.TxUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class AccountServiceImpl implements AccountService {@Autowiredprivate AccountDao accountDao;public void saveAll(Account account1, Account account2) {try {//开启事务TxUtils.startTransaction();accountDao.save(account1);//int res = 10/0;accountDao.save(account2);TxUtils.commit();}catch (Exception e){e.printStackTrace();//事务回滚TxUtils.rollback();}finally {//关闭资源TxUtils.close();}}
}