spring_three

2020-12-13 04:42

阅读:336

标签:配置   localhost   oid   tsp   new   important   ant   tco   nsf   


转账案例

坐标:

  1. org.springframework
  2. spring-context
  3. 5.0.2.RELEASE
  4. org.springframework
  5. spring-test
  6. 5.0.2.RELEASE
  7. commons-dbutils
  8. commons-dbutils
  9. 1.4
  10. mysql
  11. mysql-connector-java
  12. 5.1.6
  13. c3p0
  14. c3p0
  15. 0.9.1.2
  16. junit
  17. junit
  18. 4.12

创建实体类daomain

  1. /**
  2. * 账户的实体类
  3. */
  4. public class Account implements Serializable {
  5. private Integer id;
  6. private String name;
  7. private Float money;
  8. }

创建接口AccountDao.java

  1. /**
  2. * 账户的持久层接口
  3. */
  4. public interface AccountDao {
  5. /**
  6. * 查询所有
  7. * @return
  8. */
  9. ListAccount> findAllAccount();
  10. /**
  11. * 查询一个
  12. * @return
  13. */
  14. Account findAccountById(Integer accountId);
  15. /**
  16. * 保存
  17. * @param account
  18. */
  19. void saveAccount(Account account);
  20. /**
  21. * 更新
  22. * @param account
  23. */
  24. void updateAccount(Account account);
  25. /**
  26. * 删除
  27. * @param acccountId
  28. */
  29. void deleteAccount(Integer acccountId);
  30. /**
  31. * 根据名称查询账户
  32. * @param accountName
  33. * @return 如果有唯一的一个结果就返回,如果没有结果就返回null
  34. * 如果结果集超过一个就抛异常
  35. */
  36. Account findAccountByName(String accountName);
  37. }

创建实现类AccountDaoImpl.java

  1. /**
  2. * 账户的持久层实现类
  3. */
  4. public class AccountDaoImpl implements AccountDao {
  5. private QueryRunner runner;
  6. public ListAccount> findAllAccount() {
  7. try{
  8. return runner.query("select * from account",new BeanListHandlerAccount>(Account.class));
  9. }catch (Exception e) {
  10. throw new RuntimeException(e);
  11. }
  12. }
  13. public Account findAccountById(Integer accountId) {
  14. try{
  15. return runner.query("select * from account where id = ? ",new BeanHandlerAccount>(Account.class),accountId);
  16. }catch (Exception e) {
  17. throw new RuntimeException(e);
  18. }
  19. }
  20. public void saveAccount(Account account) {
  21. try{
  22. runner.update("insert into account(name,money)values(?,?)",account.getName(),account.getMoney());
  23. }catch (Exception e) {
  24. throw new RuntimeException(e);
  25. }
  26. }
  27. public void updateAccount(Account account) {
  28. try{
  29. runner.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
  30. }catch (Exception e) {
  31. throw new RuntimeException(e);
  32. }
  33. }
  34. public void deleteAccount(Integer accountId) {
  35. try{
  36. runner.update("delete from account where id=?",accountId);
  37. }catch (Exception e) {
  38. throw new RuntimeException(e);
  39. }
  40. }
  41. public Account findAccountByName(String accountName) {
  42. try{
  43. ListAccount> accounts = runner.query("select * from account where name = ? ",new BeanListHandlerAccount>(Account.class),accountName);
  44. if(accounts == null || accounts.size() == 0){
  45. return null;
  46. }
  47. if(accounts.size() > 1){
  48. throw new RuntimeException("结果集不唯一,数据有问题");
  49. }
  50. return accounts.get(0);
  51. }catch (Exception e) {
  52. throw new RuntimeException(e);
  53. }
  54. }
  55. }

建接口AccountService.java

  1. /**
  2. * 账户的业务层接口
  3. */
  4. public interface AccountService {
  5. /**
  6. * 查询所有
  7. * @return
  8. */
  9. ListAccount> findAllAccount();
  10. /**
  11. * 查询一个
  12. * @return
  13. */
  14. Account findAccountById(Integer accountId);
  15. /**
  16. * 保存
  17. * @param account
  18. */
  19. void saveAccount(Account account);
  20. /**
  21. * 更新
  22. * @param account
  23. */
  24. void updateAccount(Account account);
  25. /**
  26. * 删除
  27. * @param acccountId
  28. */
  29. void deleteAccount(Integer acccountId);
  30. /**
  31. * 转账
  32. * @param sourceName 转出账户名称
  33. * @param targetName 转入账户名称
  34. * @param money 转账金额
  35. */
  36. void transfer(String sourceName, String targetName, Float money);
  37. }

创建接口的实现类,AccountServiceImpl.java

  1. /**
  2. * 账户的业务层实现类
  3. *
  4. * 事务控制应该都是在业务层
  5. */
  6. public class AccountServiceImpl implements AccountService {
  7. private AccountDao accountDao;
  8. public void setAccountDao(AccountDao accountDao) {
  9. this.accountDao = accountDao;
  10. }
  11. public ListAccount> findAllAccount() {
  12. return accountDao.findAllAccount();
  13. }
  14. public Account findAccountById(Integer accountId) {
  15. return accountDao.findAccountById(accountId);
  16. }
  17. public void saveAccount(Account account) {
  18. accountDao.saveAccount(account);
  19. }
  20. public void updateAccount(Account account) {
  21. accountDao.updateAccount(account);
  22. }
  23. public void deleteAccount(Integer acccountId) {
  24. accountDao.deleteAccount(acccountId);
  25. }
  26. public void transfer(String sourceName, String targetName, Float money) {
  27. System.out.println("transfer....");
  28. //2.1根据名称查询转出账户
  29. Account source = accountDao.findAccountByName(sourceName);
  30. //2.2根据名称查询转入账户
  31. Account target = accountDao.findAccountByName(targetName);
  32. //2.3转出账户减钱
  33. source.setMoney(source.getMoney()-money);
  34. //2.4转入账户加钱
  35. target.setMoney(target.getMoney()+money);
  36. //2.5更新转出账户
  37. accountDao.updateAccount(source);
  38. int i=1/0;
  39. //2.6更新转入账户
  40. accountDao.updateAccount(target);
  41. }
  42. }

配置applicationContext.xml

  1. xml version="1.0" encoding="UTF-8"?>
  2. xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans.xsd">
  6. id="accountService" class="com.it.service.impl.AccountServiceImpl">
  7. name="accountDao" ref="accountDao">
  8. id="accountDao" class="com.it.dao.impl.AccountDaoImpl">
  9. name="runner" ref="runner">
  10. id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
  11. name="ds" ref="dataSource">
  12. id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
  13. name="driverClass" value="com.mysql.jdbc.Driver">
  14. name="jdbcUrl" value="jdbc:mysql://localhost:3306/itcastspring">
  15. name="user" value="root">
  16. name="password" value="root">

测试AccountServiceTest.java

  1. /**
  2. * 使用Junit单元测试:测试我们的配置
  3. */
  4. @RunWith(SpringJUnit4ClassRunner.class)
  5. @ContextConfiguration(locations = "classpath:applicationContext.xml")
  6. public class AccountServiceTest {
  7. @Autowired
  8. private AccountService as;
  9. @Test
  10. public void testTransfer(){
  11. as.transfer("aaa","bbb",100f);
  12. }
  13. }

事务被自动控制了。换言之,我们使用了connection对象的setAutoCommit(true)


添加事务

技术图片

如果在AccountServiceImpl.java中的transfer方法中,抛出一个异常。此时事务不会回滚,原因是DBUtils每个操作数据都是获取一个连接,每个连接的事务都是独立的,且默认是自动提交。

解决方案:

需要使用ThreadLocal对象把Connection和当前线程绑定,从而使一个线程中只能有一个能控制事务的连接对象。

ConnectionUtils.java

  1. /**
  2. * 连接的工具类,它用于从数据源中获取一个连接,并且实现和线程的绑定
  3. */
  4. public class ConnectionUtils {
  5. private ThreadLocalConnection> tl = new ThreadLocalConnection>();
  6. //注入数据源
  7. private DataSource dataSource;
  8. public void setDataSource(DataSource dataSource) {
  9. this.dataSource = dataSource;
  10. }
  11. /**
  12. * 获取当前线程上的连接,
  13. * @return
  14. */
  15. public Connection getThreadConnection() {
  16. try{
  17. //1.先从ThreadLocal上获取
  18. Connection conn = tl.get();
  19. //2.判断当前线程上是否有连接
  20. if (conn == null) {
  21. //3.从数据源中获取一个连接,并且存入ThreadLocal中
  22. conn = dataSource.getConnection();
  23. tl.set(conn);
  24. }
  25. //4.返回当前线程上的连接
  26. return conn;
  27. }catch (Exception e){
  28. throw new RuntimeException(e);
  29. }
  30. }
  31. /**
  32. * 把连接和线程解绑(在当前线程结束的时候执行)
  33. */
  34. public void removeConnection(){
  35. tl.remove();
  36. }
  37. }

TransactionManager.java

和事务管理相关的工具类,它包含了,开启事务,提交事务,回滚事务和释放连接

  1. /**
  2. * 和事务管理相关的工具类,它包含了,开启事务,提交事务,回滚事务和释放连接
  3. */
  4. public class TransactionManager {
  5. private ConnectionUtils connectionUtils;
  6. public void setConnectionUtils(ConnectionUtils connectionUtils) {
  7. this.connectionUtils = connectionUtils;
  8. }
  9. /**
  10. * 开启事务
  11. */
  12. public void beginTransaction(){
  13. try {
  14. connectionUtils.getThreadConnection().setAutoCommit(false);
  15. }catch (Exception e){
  16. e.printStackTrace();
  17. }
  18. }
  19. /**
  20. * 提交事务
  21. */
  22. public void commit(){
  23. try {
  24. connectionUtils.getThreadConnection().commit();
  25. }catch (Exception e){
  26. e.printStackTrace();
  27. }
  28. }
  29. /**
  30. * 回滚事务
  31. */
  32. public void rollback(){
  33. try {
  34. connectionUtils.getThreadConnection().rollback();
  35. }catch (Exception e){
  36. e.printStackTrace();
  37. }
  38. }
  39. /**
  40. * 释放连接
  41. */
  42. public void release(){
  43. try {
  44. connectionUtils.getThreadConnection().close();//把连接还回连接池中
  45. connectionUtils.removeConnection();//线程和连接解绑
  46. }catch (Exception e){
  47. e.printStackTrace();
  48. }
  49. }
  50. }

配置AccountDaoImpl.java

注入连接工具对象,使得操作数据库从同一个连接中获取

  1. /**
  2. * 账户的持久层实现类
  3. */
  4. public class AccountDaoImpl implements AccountDao {
  5. private QueryRunner runner;
  6. private ConnectionUtils connectionUtils;
  7. public void setConnectionUtils(ConnectionUtils connectionUtils) {
  8. this.connectionUtils = connectionUtils;
  9. }
  10. public void setRunner(QueryRunner runner) {
  11. this.runner = runner;
  12. }
  13. public ListAccount> findAllAccount() {
  14. try{
  15. return runner.query(connectionUtils.getThreadConnection(),"select * from account",new BeanListHandlerAccount>(Account.class));
  16. }catch (Exception e) {
  17. throw new RuntimeException(e);
  18. }
  19. }
  20. public Account findAccountById(Integer accountId) {
  21. try{
  22. return runner.query(connectionUtils.getThreadConnection(),"select * from account where id = ? ",new BeanHandlerAccount>(Account.class),accountId);
  23. }catch (Exception e) {
  24. throw new RuntimeException(e);
  25. }
  26. }
  27. public void saveAccount(Account account) {
  28. try{
  29. runner.update


评论


亲,登录后才可以留言!