[JAVAEE]实验05:Spring事务管理

作者: Topus | 来源:发表于2019-04-04 16:41 被阅读0次

    1.Spring JDBC

    1.1applicationContext.xml内配置好数据库相关信息

     <!-- 指定需要扫描的包(包括子包),使注解生效 -->
       <context:component-scan base-package="com.ch5"/>
       <!-- 配置数据源 -->
       <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <!-- MySQL数据库驱动 -->
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <!-- 连接数据库的URL -->
            <property name="url" value="jdbc:mysql://localhost:3306/springtest?characterEncoding=utf8"/>
            <!-- 连接数据库的用户名 -->
            <property name="username" value="root"/>
            <!-- 连接数据库的密码 -->
            <property name="password" value="363316495"/>
       </bean>
       <!-- 配置JDBC模板 -->
       <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"/>
       </bean>
    

    1.2创建实体类MyUser

    public class MyUser {
        private Integer uid;
        private String uname;
        private String usex;
        public Integer getUid() {
            return uid;
        }
        public void setUid(Integer uid) {
            this.uid = uid;
        }
        public String getUname() {
            return uname;
        }
        public void setUname(String uname) {
            this.uname = uname;
        }
        public String getUsex() {
            return usex;
        }
        public void setUsex(String usex) {
            this.usex = usex;
        }
        public String toString() {
            return "myUser [uid=" + uid +", uname=" + uname + ", usex=" + usex + "]";
        }
    }
    

    1.3创建数据库访问层TestDao
    接口类:

    package ch5;
    import java.util.List;
    public interface TestDao {
        public int update(String sql, Object[] param);
        public List<MyUser> query(String sql, Object[] param);
    }
    实现类:
    @Repository("testDao")
    public class TestDaoImpl implements TestDao{
        //自动装配
         @Autowired
        //使用配置文件中的JDBC(相当于依赖注入了)
        private JdbcTemplate jdbcTemplate;
        
         //更新方法
        @Override
        public int update(String sql, Object[] param) {
            return jdbcTemplate.update(sql, param);
        }
        
        //查询方法
        @Override
        public List<MyUser> query(String sql, Object[] param) {
            RowMapper<MyUser> rowMapper = new BeanPropertyRowMapper<MyUser>(MyUser.class);
            return jdbcTemplate.query(sql, rowMapper, param);
        }
    }
    

    1.4测试:

        public static void main(String[] args) {
            @SuppressWarnings("resource")
            ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
            //从容器中获取增强后的目标对象
            TestDao td = (TestDao)appCon.getBean("testDao");
            
            //插入的sql
            //暂时没有在这里发现问题:
            //UID为主键,这里设置为空,不会出现问题,原因是:mysql数据库里面可以勾选主键自动增长
            String insertSql = "insert into user values(null,?,?)";
            //数组param的值与insertSql语句一一对应
            //此处我的mysql不支持中文字符,改成了英文字符,不影响
            Object param1[] = {"chenheng1", "nan"};
            Object param2[] = {"chenheng2", "nv"};
            Object param3[] = {"chenheng3", "nan"};
            Object param4[] = {"chenheng4", "nv"};
            //添加用户
            td.update(insertSql, param1);
            td.update(insertSql, param2);
            td.update(insertSql, param3);
            td.update(insertSql, param4);
            
            //查询用户的sql
            String selectSql ="select * from user";
            List<MyUser> list = td.query(selectSql, null);
            for(MyUser mu : list) {
                System.out.println(mu);
            }
        }
    }
    
    1

    2.编程式事务管理

    (1)基于底层API的编程式事务管理
    2.1.1 applicationContext.xml内配置事务管理器

    <!-- 为数据源添加事务管理器 -->
       <bean id="txManager"   
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager" <property name="dataSource" ref="dataSource" />   
       </bean>
    

    2.1.2 创建数据访问类
    //数据访问类

    @Repository("codeTransaction")
    public class CodeTransaction {
        @Autowired
        // 使用配置文件中的JDBC模板
        private JdbcTemplate jdbcTemplate;
        //DataSourceTransactionManager是PlatformTransactionManager接口的实现类
        @Autowired
        private DataSourceTransactionManager txManager;
        
        //定义test方法
        public String test() {
            
            // 默认事务定义,例如隔离级别、传播行为
            TransactionDefinition tf = new DefaultTransactionDefinition();
            //开启事务ts
            TransactionStatus ts = txManager.getTransaction(tf);
            
            String message = "ִ执行成功,没有事务回滚";
            try {
                // 删除表中数据
                String sql = " delete from user  ";
                //添加表中数据
                String sql1 = " insert into user values(?,?,?) ";
                Object param[] = { 1, "topus", "nan" };
                // 先删除数据
                jdbcTemplate.update(sql);
                //添加一条数据
                jdbcTemplate.update(sql1, param);
                // 添加相同的一条数据
                jdbcTemplate.update(sql1, param);
                //提交事务
                txManager.commit(ts);
            } catch (Exception e) {
                // 出现异常,事务回滚
                txManager.rollback(ts);
                message = "主键重复,事务回滚";
                e.printStackTrace();
            }
            //返回的是执行成功与否的消息
            return message;
        }
    }
    

    2.2.3测试

    public class TestCodeTransaction {
        public static void main(String[] args) {
            @SuppressWarnings("resource")
            ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
            CodeTransaction ct = (CodeTransaction)appCon.getBean("codeTransaction");
            String result = ct.test();
            System.out.println(result);
        }
    }
    
    不重复添加 success 数据表 重复添加 回滚

    (2)基于TranesactionTemplate的编程式事务管理

    2.2.1为事务管理器添加事务模板
     <!-- 为事务管理器txManager创建transactionTemplate -->
        <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">  
            <property name="transactionManager" ref="txManager"/>  
        </bean>
    

    2.2.2 创建数据访问类

    @Repository("transactionTemplateDao")
    public class TransactionTemplateDao {
        @Autowired
        //使用配置文件中的jdbc
        private JdbcTemplate jdbcTemplate;
        @Autowired
        private TransactionTemplate transactionTemplate;
        String message = "";
        public String test() {
            //匿名内部类
            transactionTemplate.execute(new TransactionCallback<Object>(){
                @Override
                public Object doInTransaction(TransactionStatus arg0) {
                    //删除
                    String sql = " delete from user  ";
                    //添加
                    String sql1 = " insert into user values(?,?,?) ";
                    Object param[] = {
                            1,
                            "zyz",
                            "nan"
                    };
                    try{
                        //先删除数据
                        jdbcTemplate.update(sql);
                        //添加一条数据
                        jdbcTemplate.update(sql1, param);
                        //添加一条重复数据
                        jdbcTemplate.update(sql1, param);
                        message = "执行成功没有事务回滚ִ";
                    }catch(Exception e){
                        message = "主键重复,事务回滚";
                        e.printStackTrace();
                    }
                    return message;
                }
            });
            return message;
        }
    }
    

    2.2.3 创建测试类

    public class TransactionTemplateTest {
        public static void main(String[] args) {
            @SuppressWarnings("resource")
            ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
            TransactionTemplateDao ct = (TransactionTemplateDao)appCon.getBean("transactionTemplateDao");
            String result = ct.test();
            System.out.println(result);
        }
    }
    
    数据库 不重复 成功 重复 回滚

    3.声明式事务管理

    (基于AOP技术实现的事务管理,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务)

    (1)xml
    3.1.1创建Dao层

    public interface TestDao {
        public int save(String sql, Object param[]);
        public int delete(String sql, Object param[]);
    }
    @Repository("TestDao")
    public class TestDaoImpl implements TestDao{
        @Autowired
        private JdbcTemplate jdbcTemplate;
        @Override
        public int save(String sql, Object[] param) {
            return jdbcTemplate.update(sql,param);
        }
        @Override
        public int delete(String sql, Object[] param) {
            return jdbcTemplate.update(sql,param);
        }
    }
    

    3.1.2创建service层

    public class TestServiceImpl implements TestService{
        @Autowired
        private TestDao testDao;
        @Override
    //  这里调用Dao层的save和delete方法,参数为sql和param,等控制层在传入sql语句
        public int save(String sql, Object[] param) {
            return testDao.save(sql, param);
        }
        @Override
        public int delete(String sql, Object[] param) {
            return testDao.delete(sql, param);
        }
    }
    

    3.1.3创建controller层

        private TestService testService;
        public String test() {
    //      此处在加入sql语句
            String message = "";
            String deleteSql ="delete from user";
            String saveSql = "insert into user values(?,?,?)";
            Object param[] = {1,"topus","nan"};
            try{
                testService.delete(deleteSql, null);
                testService.save(saveSql, param);
                //重复插入相同主键的数据
                testService.save(saveSql, param);
            }catch(Exception e){
                message = "主键重复,回滚";
                e.printStackTrace();
            }
            return message;
        }
    }
    

    3.1.4创建配置文件
    在xml里面使用<tx:advice>编写通知声明事务
    使用<aop:config>编写AOP让spring自动对目标对象生成代理

     <!-- 指定需要扫描的包(包括子包),使注解生效 -->
       <context:component-scan base-package="com.statement"/>
       <!-- 配置数据源 -->
       <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <!-- MySQL数据库驱动 -->
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <!-- 连接数据库的URL -->
            <property name="url" value="jdbc:mysql://localhost:3306/springtest?characterEncoding=utf8"/>
            <!-- 连接数据库的用户名 -->
            <property name="username" value="root"/>
            <!-- 连接数据库的密码 -->
            <property name="password" value="root"/>
       </bean>
       <!-- 配置JDBC模板 -->
       <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"/>
       </bean>
       <!-- 为数据源添加事务管理器 -->
       <bean id="txManager"   
             class="org.springframework.jdbc.datasource.DataSourceTransactionManager">   
             <property name="dataSource" ref="dataSource" />   
       </bean> 
       <!-- 编写通知声明事务 -->
       <tx:advice id="myAdvice" transaction-manager="txManager">
            <tx:attributes>
                <!-- *表示任意方法 -->
                <tx:method name="*"/>
            </tx:attributes>
       </tx:advice>
       <!-- 编写AOP,让Spring自动对目标对象生成代理,需要使用AspectJ的表达式 -->
       <aop:config>
            <!-- 定义切入点 -->
            <aop:pointcut expression="execution(* com.statement.service.*.*())" id="txPointCut"/>
            <!-- 切面:将切入点与通知关联 -->
            <aop:advisor advice-ref="myAdvice" pointcut-ref="txPointCut"/>
       </aop:config>
    </beans>
    

    3.1.6测试

    public static void main(String[] args) {
            @SuppressWarnings("resource")
            ApplicationContext appCon = new ClassPathXmlApplicationContext("/com/statement/xml/XMLstatementapplicationContext.xml");
            StatementController ct = (StatementController)appCon.getBean("statementController");
            String result = ct.test();
            System.out.println(result);
        }
    

    (2)基于transactional注解的声明式事务管理
    3.2.1创建配置文件

       <!-- 指定需要扫描的包(包括子包),使注解生效 -->
       <context:component-scan base-package="com.statement"/>
       <!-- 配置数据源 -->
       <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <!-- MySQL数据库驱动 -->
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <!-- 连接数据库的URL -->
            <property name="url" value="jdbc:mysql://localhost:3306/springtest?characterEncoding=utf8"/>
            <!-- 连接数据库的用户名 -->
            <property name="username" value="root"/>
            <!-- 连接数据库的密码 -->
            <property name="password" value="root"/>
       </bean>
       <!-- 配置JDBC模板 -->
       <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"/>
       </bean>
       <!-- 为数据源添加事务管理器 -->
       <bean id="txManager"   
             class="org.springframework.jdbc.datasource.DataSourceTransactionManager">   
             <property name="dataSource" ref="dataSource" />   
       </bean> 
       <!-- 为事务管理器注册注解驱动 -->
       <tx:annotation-driven transaction-manager="txManager" />
    </beans>
    

    3.2.2在service层添加注解@Transactional
    //加上注解@Transactional,就可以指定这个类需要受Spring的事务管理
    //注意@Transactional智能针对pulic属性范围内的方法添加

    @Transactional
    public class TestServiceImpl implements TestService{
        @Autowired
        private TestDao testDao;
        @Override
    //  这里调用Dao层的save和delete方法,参数为sql和param,等控制层在传入sql语句
        public int save(String sql, Object[] param) {
            return testDao.save(sql, param);
        }
        @Override
        public int delete(String sql, Object[] param) {
            return testDao.delete(sql, param);
        }
    }
    

    3.2.3在事务处理中捕获异常
    修改注解

    @Transactional(rollbackFor = (Exception.class))
    //指定回滚生效的异常类
    
    1 2

    其实本质上问题在于书内的try catch的异常捕获写在的service层,但是在默认情况下,Spring只在(发生未被捕获的RuntimeException时)才回滚事务,此时如果想在事务处理中捕获异常就必须指定回滚生效的异常类.

    相关文章

      网友评论

        本文标题:[JAVAEE]实验05:Spring事务管理

        本文链接:https://www.haomeiwen.com/subject/vprqiqtx.html