spring_three
2020-12-13 04:42
标签:配置 localhost oid tsp new important ant tco nsf 坐标: 创建实体类daomain 创建接口AccountDao.java 创建实现类AccountDaoImpl.java 建接口AccountService.java 创建接口的实现类,AccountServiceImpl.java 配置applicationContext.xml 测试AccountServiceTest.java 事务被自动控制了。换言之,我们使用了connection对象的setAutoCommit(true) 如果在AccountServiceImpl.java中的transfer方法中,抛出一个异常。此时事务不会回滚,原因是DBUtils每个操作数据都是获取一个连接,每个连接的事务都是独立的,且默认是自动提交。 解决方案: 需要使用ThreadLocal对象把Connection和当前线程绑定,从而使一个线程中只能有一个能控制事务的连接对象。 ConnectionUtils.java TransactionManager.java 和事务管理相关的工具类,它包含了,开启事务,提交事务,回滚事务和释放连接 配置AccountDaoImpl.java 注入连接工具对象,使得操作数据库从同一个连接中获取转账案例
spring-context spring-test commons-dbutils mysql-connector-java c3p0 junit
/*** 账户的实体类*/public class Account implements Serializable { private Integer id; private String name; private Float money;}
/*** 账户的持久层接口*/public interface AccountDao { /** * 查询所有 * @return */ ListAccount> findAllAccount(); /** * 查询一个 * @return */ Account findAccountById(Integer accountId); /** * 保存 * @param account */ void saveAccount(Account account); /** * 更新 * @param account */ void updateAccount(Account account); /** * 删除 * @param acccountId */ void deleteAccount(Integer acccountId); /** * 根据名称查询账户 * @param accountName * @return 如果有唯一的一个结果就返回,如果没有结果就返回null * 如果结果集超过一个就抛异常 */ Account findAccountByName(String accountName);}
/*** 账户的持久层实现类*/public class AccountDaoImpl implements AccountDao { private QueryRunner runner; public ListAccount> findAllAccount() { try{ return runner.query("select * from account",new BeanListHandlerAccount>(Account.class)); }catch (Exception e) { throw new RuntimeException(e); } } public Account findAccountById(Integer accountId) { try{ return runner.query("select * from account where id = ? ",new BeanHandlerAccount>(Account.class),accountId); }catch (Exception e) { throw new RuntimeException(e); } } public void saveAccount(Account account) { try{ runner.update("insert into account(name,money)values(?,?)",account.getName(),account.getMoney()); }catch (Exception e) { throw new RuntimeException(e); } } public void updateAccount(Account account) { try{ runner.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId()); }catch (Exception e) { throw new RuntimeException(e); } } public void deleteAccount(Integer accountId) { try{ runner.update("delete from account where id=?",accountId); }catch (Exception e) { throw new RuntimeException(e); } } public Account findAccountByName(String accountName) { try{ ListAccount> accounts = runner.query("select * from account where name = ? ",new BeanListHandlerAccount>(Account.class),accountName); if(accounts == null || accounts.size() == 0){ return null; } if(accounts.size() > 1){ throw new RuntimeException("结果集不唯一,数据有问题"); } return accounts.get(0); }catch (Exception e) { throw new RuntimeException(e); } }}
/*** 账户的业务层接口*/public interface AccountService { /** * 查询所有 * @return */ ListAccount> findAllAccount(); /** * 查询一个 * @return */ Account findAccountById(Integer accountId); /** * 保存 * @param account */ void saveAccount(Account account); /** * 更新 * @param account */ void updateAccount(Account account); /** * 删除 * @param acccountId */ void deleteAccount(Integer acccountId); /** * 转账 * @param sourceName 转出账户名称 * @param targetName 转入账户名称 * @param money 转账金额 */ void transfer(String sourceName, String targetName, Float money);}
/*** 账户的业务层实现类** 事务控制应该都是在业务层*/public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } public ListAccount> findAllAccount() { return accountDao.findAllAccount(); } public Account findAccountById(Integer accountId) { return accountDao.findAccountById(accountId); } public void saveAccount(Account account) { accountDao.saveAccount(account); } public void updateAccount(Account account) { accountDao.updateAccount(account); } public void deleteAccount(Integer acccountId) { accountDao.deleteAccount(acccountId); } public void transfer(String sourceName, String targetName, Float money) { System.out.println("transfer...."); //2.1根据名称查询转出账户 Account source = accountDao.findAccountByName(sourceName); //2.2根据名称查询转入账户 Account target = accountDao.findAccountByName(targetName); //2.3转出账户减钱 source.setMoney(source.getMoney()-money); //2.4转入账户加钱 target.setMoney(target.getMoney()+money); //2.5更新转出账户 accountDao.updateAccount(source); int i=1/0; //2.6更新转入账户 accountDao.updateAccount(target); }}
xml version="1.0" encoding="UTF-8"?> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
/*** 使用Junit单元测试:测试我们的配置*/@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = "classpath:applicationContext.xml")public class AccountServiceTest { @Autowired private AccountService as; @Test public void testTransfer(){ as.transfer("aaa","bbb",100f); }}
添加事务

/*** 连接的工具类,它用于从数据源中获取一个连接,并且实现和线程的绑定*/public class ConnectionUtils { private ThreadLocalConnection> tl = new ThreadLocalConnection>(); //注入数据源 private DataSource dataSource; public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } /** * 获取当前线程上的连接, * @return */ public Connection getThreadConnection() { try{ //1.先从ThreadLocal上获取 Connection conn = tl.get(); //2.判断当前线程上是否有连接 if (conn == null) { //3.从数据源中获取一个连接,并且存入ThreadLocal中 conn = dataSource.getConnection(); tl.set(conn); } //4.返回当前线程上的连接 return conn; }catch (Exception e){ throw new RuntimeException(e); } } /** * 把连接和线程解绑(在当前线程结束的时候执行) */ public void removeConnection(){ tl.remove(); }}
/*** 和事务管理相关的工具类,它包含了,开启事务,提交事务,回滚事务和释放连接*/public class TransactionManager { private ConnectionUtils connectionUtils; public void setConnectionUtils(ConnectionUtils connectionUtils) { this.connectionUtils = connectionUtils; } /** * 开启事务 */ public void beginTransaction(){ try { connectionUtils.getThreadConnection().setAutoCommit(false); }catch (Exception e){ e.printStackTrace(); } } /** * 提交事务 */ public void commit(){ try { connectionUtils.getThreadConnection().commit(); }catch (Exception e){ e.printStackTrace(); } } /** * 回滚事务 */ public void rollback(){ try { connectionUtils.getThreadConnection().rollback(); }catch (Exception e){ e.printStackTrace(); } } /** * 释放连接 */ public void release(){ try { connectionUtils.getThreadConnection().close();//把连接还回连接池中 connectionUtils.removeConnection();//线程和连接解绑 }catch (Exception e){ e.printStackTrace(); } }}
/*** 账户的持久层实现类*/public class AccountDaoImpl implements AccountDao { private QueryRunner runner; private ConnectionUtils connectionUtils; public void setConnectionUtils(ConnectionUtils connectionUtils) { this.connectionUtils = connectionUtils; } public void setRunner(QueryRunner runner) { this.runner = runner; } public ListAccount> findAllAccount() { try{ return runner.query(connectionUtils.getThreadConnection(),"select * from account",new BeanListHandlerAccount>(Account.class)); }catch (Exception e) { throw new RuntimeException(e); } } public Account findAccountById(Integer accountId) { try{ return runner.query(connectionUtils.getThreadConnection(),"select * from account where id = ? ",new BeanHandlerAccount>(Account.class),accountId); }catch (Exception e) { throw new RuntimeException(e); } } public void saveAccount(Account account) { try{ runner.update