四种控制事务的方法

xiaoxiao2021-02-28  112

四种控制事务的方法

第一种

在DAO层控制事务

新建项目tx1

1.导入所需jar包

commons-dbcp-1.4.jar commons-dbutils-1.4.jar commons-pool-1.5.6.jar mysql-connector-java-5.0.8-bin.jar

2.新建com.view包,模拟客户端调用action

package com.view; import com.service.BusinessService; import com.service.impl.BusinessServiceImpl; public class Client { //模拟action中调用service public static void main(String[] args) { BusinessService s = new BusinessServiceImpl(); s.transfer("aaa","bbb",100); } }

3.新建com.service包,写业务接口

package com.service; public interface BusinessService { /** * 模拟转账 * @param from 转出的账户 * @param to 目标账户 * @param money 交易金额 */ void transfer(String from, String to, float money); }

4.新建com.service.impl包,实现业务接口

package com.service.impl; import java.sql.Connection; import com.dao.AccountDao; import com.dao.impl.AccountDaoImpl; import com.service.BusinessService; import com.utils.DBCPUtil; public class BusinessServiceImpl implements BusinessService { private AccountDao dao = new AccountDaoImpl(); @Override public void transfer(String from, String to, float money) { dao.transfer(from, to, money); } }

5.新建com.dao包,写数据接口DAO

package com.dao; public interface AccountDao { /** * 转账,这里有点牵扯到业务的意思 * @param from * @param to * @param money */ void transfer(String from, String to, float money); }

6.新建com.dao.impl,写数据接口DAO的实现

package com.dao.impl; import java.sql.Connection; import java.sql.SQLException; import org.apache.commons.dbutils.QueryRunner; import com.dao.AccountDao; import com.utils.DBCPUtil; public class AccountDaoImpl implements AccountDao { private QueryRunner qr = new QueryRunner(); @Override public void transfer(String from, String to, float money) { Connection conn = null; try { conn =DBCPUtil.getConnection(); conn.setAutoCommit(false); qr.update(conn, "update account set money=money-? where name=?",money,from); qr.update(conn, "update account set money=money+? where name=?",money,to); } catch (Exception e) { if(conn!=null){ try { conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } } }finally{ if(conn!=null){ try { conn.commit(); conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }

7.工具类

package com.utils; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; public class DBCPUtil { private static DataSource dataSource; static{ try { InputStream in = DBCPUtil.class.getClassLoader().getResourceAsStream("dbcpconfig.properties"); Properties props = new Properties(); props.load(in); dataSource = BasicDataSourceFactory.createDataSource(props); } catch (Exception e) { throw new ExceptionInInitializerError(e); } } public static DataSource getDataSource(){ return dataSource; } //获得连接 public static Connection getConnection(){ try { return dataSource.getConnection(); } catch (SQLException e) { throw new RuntimeException(e); } } }

8.dbconfig.properties

driverClassName=com.mysql.jdbc.Driver url=jdbc\:mysql\://localhost\:3306/jdbc username=root password=19941119liu initialSize=10 maxActive=50 maxIdle=20 minIdle=5 maxWait=60000 connectionProperties=useUnicode=true;characterEncoding=utf8 defaultAutoCommit=true defaultReadOnly= defaultTransactionIsolation=REPEATABLE_READ

第二种

业务层控制事务

拷贝tx1项目到tx2

1.新建com.domain包,描述实体Account

package com.domain; public class Account { private int id; private String name; private float money; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public float getMoney() { return money; } public void setMoney(float money) { this.money = money; } }

2.修改AccountDao.java

AccountDao不在涉及到业务,只做crud操作

package com.dao; import com.domain.Account; public interface AccountDao { /** * 根据户名查询账户 * @param accountName * @return */ Account findByName(String accountName); /** * 更新账户 * @param account */ void updateAccount(Account account); }

3.修改dao的实现

package com.dao.impl; import java.sql.Connection; import java.sql.SQLException; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import com.dao.AccountDao; import com.domain.Account; import com.utils.DBCPUtil; public class AccountDaoImpl implements AccountDao { private QueryRunner qr = new QueryRunner(); private Connection conn; public AccountDaoImpl(Connection conn){ this.conn = conn; } //查账户 @Override public Account findByName(String accountName) { try { return qr.query(conn, "select * from account where name=?", new BeanHandler<Account>(Account.class),accountName); } catch (Exception e) { throw new RuntimeException(e); } } //改账户 @Override public void updateAccount(Account account) { try { qr.update(conn, "update account set money=? where id=?",account.getMoney(),account.getId()); } catch (Exception e) { throw new RuntimeException(e); } } }

4.业务接口不变,只需修改业务实现

package com.service.impl; import java.sql.Connection; import java.sql.SQLException; import com.dao.AccountDao; import com.dao.impl.AccountDaoImpl; import com.domain.Account; import com.service.BusinessService; import com.utils.DBCPUtil; //业务层控制事务 public class BusinessServiceImpl implements BusinessService { @Override public void transfer(String from, String to, float money) { Connection conn = null; try { //拿连接 conn = DBCPUtil.getConnection(); conn.setAutoCommit(false); AccountDao dao = new AccountDaoImpl(conn); //调取DAO查找两个账户 Account fromAccount = dao.findByName(from); Account toAccount = dao.findByName(to); fromAccount.setMoney(fromAccount.getMoney() - money); toAccount.setMoney(toAccount.getMoney() + money); //对账户进行更改 dao.updateAccount(fromAccount); dao.updateAccount(toAccount); } catch (Exception e) { if (conn != null) { try { conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } } e.printStackTrace(); }finally { if (conn != null) { try { conn.commit(); conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }

第三种

抽取工具类,封装与事务有关的方法

拷贝tx2项目到tx3项目

1.在com.utils包中新建TransactionManager.java

package com.utils; import java.sql.Connection; import java.sql.SQLException; //封装所有与事务有关的方法 public class TransactionManager { private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>(); //获取连接 public static Connection getConnection(){ //先从当前线程中获取连接 Connection conn = tl.get(); if(conn == null){ //如果没有则从数据源中拿 conn = DBCPUtil.getConnection(); tl.set(conn); } return conn; } //开启事务 public static void startTransaction(){ try { Connection conn = getConnection(); conn.setAutoCommit(false); } catch (SQLException e) { e.printStackTrace(); } } //回滚 public static void rollback(){ Connection conn = getConnection(); try { conn.rollback(); } catch (SQLException e) { e.printStackTrace(); } } //释放资源 public static void release(){ try { Connection conn = getConnection(); conn.close(); tl.remove(); } catch (SQLException e) { e.printStackTrace(); } } //提交事务 public static void commit(){ try { Connection conn = getConnection(); conn.commit(); } catch (SQLException e) { e.printStackTrace(); } } }

3.重写业务的实现

package com.service.impl; import java.sql.Connection; import java.sql.SQLException; import com.dao.AccountDao; import com.dao.impl.AccountDaoImpl; import com.domain.Account; import com.service.BusinessService; import com.utils.DBCPUtil; import com.utils.TransactionManager; //业务层控制事务 public class BusinessServiceImpl implements BusinessService { private AccountDao dao = new AccountDaoImpl(); @Override public void transfer(String from, String to, float money) { try { TransactionManager.startTransaction(); Account sAccount = dao.findByName(from); Account tAccount = dao.findByName(to); sAccount.setMoney(sAccount.getMoney() - money); tAccount.setMoney(tAccount.getMoney() + money); dao.updateAccount(sAccount); dao.updateAccount(tAccount); } catch (Exception e) { TransactionManager.rollback(); }finally{ TransactionManager.commit(); TransactionManager.release(); } } }

第四种

AOP控制事务

通过AOP拦截业务方法,给业务方法加上事务的方法

1.首先修改业务方法的实现,修改transfer()方法

package com.service.impl; import java.sql.Connection; import java.sql.SQLException; import com.dao.AccountDao; import com.dao.impl.AccountDaoImpl; import com.domain.Account; import com.service.BusinessService; import com.utils.DBCPUtil; import com.utils.TransactionManager; //我不再管事务了,我只管我的业务逻辑 public class BusinessServiceImpl implements BusinessService { private AccountDao dao = new AccountDaoImpl(); @Override public void transfer(String from, String to, float money) { Account sAccount = dao.findByName(from); Account tAccount = dao.findByName(to); sAccount.setMoney(sAccount.getMoney() - money); tAccount.setMoney(tAccount.getMoney() + money); dao.updateAccount(sAccount); dao.updateAccount(tAccount); } }

2.客户端再调用的时候,调用的是工厂产生的代理对象,代理对象的方法结合了业务方法和事务方法

package com.utils; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import com.service.BusinessService; import com.service.impl.BusinessServiceImpl; //AOP控制事务 public class BeanFactory { public static BusinessService getBusinessService(){ final BusinessService s = new BusinessServiceImpl(); BusinessService proxyS = (BusinessService) Proxy.newProxyInstance(s.getClass().getClassLoader(), s.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { TransactionManager.startTransaction(); Object rtValue = method.invoke(s, args); return rtValue; } catch (Exception e) { TransactionManager.rollback(); throw new RuntimeException(e); }finally{ TransactionManager.commit(); TransactionManager.release(); } } }); return proxyS; } }

3.客户端通过工厂拿到业务实例

package com.view; import com.service.BusinessService; import com.service.impl.BusinessServiceImpl; import com.utils.BeanFactory; public class Client { //模拟action中调用service public static void main(String[] args) { BusinessService s = BeanFactory.getBusinessService(); s.transfer("aaa","bbb",100); } }
转载请注明原文地址: https://www.6miu.com/read-26612.html

最新回复(0)