how2j.cn

相关下载
文件名 文件大小
aspectjweaver.jar 1m
ssm.rar 12m
使用站长秘制下载工具

步骤 1 : 先运行,看到效果,再学习   
步骤 2 : 模仿和排错   
步骤 3 : 本知识点效果   
步骤 4 : MYSQL 表的类型必须是INNODB才支持事务   
步骤 5 : 导入JAR包   
步骤 6 : CategoryService   
步骤 7 : CategoryServiceImpl   
步骤 8 : 修改测试类,观察效果   
步骤 9 : 进行事务配置   
步骤 10 : 使用注解方式   
步骤 11 : 运行测试类,观察效果   
步骤 12 : 使用XML配置方式   
步骤 13 : 运行测试类,观察效果   
步骤 14 : 为什么不启动Web应用进行测试?   

步骤 1 :

先运行,看到效果,再学习

老规矩,先下载右上角的可运行项目,配置运行起来,确认可用之后,再学习做了哪些步骤以达到这样的效果。

效果: 运行MybatisTest故意制造错误,会观察到被事务管理的方法:addTwo,因为某一条sql语句失败了,另一个sql语句也没有成功生效(要么都成功,要么都失败)
步骤 2 :

模仿和排错

在确保可运行项目能够正确无误地运行之后,再严格照着教程的步骤,对代码模仿一遍。
模仿过程难免代码有出入,导致无法得到期望的运行结果,此时此刻通过比较正确答案 ( 可运行项目 ) 和自己的代码,来定位问题所在。
采用这种方式,学习有效果,排错有效率,可以较为明显地提升学习速度,跨过学习路上的各个槛。

推荐使用diffmerge软件,进行文件夹比较。把你自己做的项目文件夹,和我的可运行项目文件夹进行比较。
这个软件很牛逼的,可以知道文件夹里哪两个文件不对,并且很明显地标记出来
这里提供了绿色安装和使用教程:diffmerge 下载和使用教程
步骤 3 :

本知识点效果

本知识点将演示,使用事务之前和使用事务之后的效果区别,以及分别使用注解和XML方式在SSM中配置事务。

本知识点基于SSM整合的基础上进行
步骤 4 :

MYSQL 表的类型必须是INNODB才支持事务

在Mysql中,只有当表的类型是INNODB的时候,才支持事务,所以需要把表的类型设置为INNODB,否则无法观察到事务.

修改表的类型为INNODB的SQL:

alter table category_ ENGINE = innodb;


查看表的类型的SQL

show table status from how2java;


不过有个前提,就是当前的MYSQL服务器本身要支持INNODB,如果不支持,请看 开启MYSQL INNODB的办法
步骤 5 :

导入JAR包

做事务管理需要额外的jar才行,所以先在右上角下载aspectjweaver.jar,
把jar包导入到项目中,导包办法:右键 project->properties->java build path->libaries->add external jars
导入JAR包
步骤 6 :

CategoryService

为接口CategoryService增加addTwo和deleteAll方法
package com.how2java.service; import java.util.List; import com.how2java.pojo.Category; public interface CategoryService { List<Category> list(); void addTwo(); void deleteAll(); }
package com.how2java.service;

import java.util.List;

import com.how2java.pojo.Category;

public interface CategoryService {

	List<Category> list();
	
	void addTwo();

	void deleteAll();

}
步骤 7 :

CategoryServiceImpl

在CategoryServiceImpl中实现deleteAll和addTwo方法。
分别做如下事情:
1. 删除所有Category
2. 增加2个Category对象,第一个可以正常增加,第二个因为名字太长,加入会失败。
package com.how2java.service.impl; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.how2java.mapper.CategoryMapper; import com.how2java.pojo.Category; import com.how2java.service.CategoryService; @Service public class CategoryServiceImpl implements CategoryService{ @Autowired CategoryMapper categoryMapper; public List<Category> list(){ return categoryMapper.list(); } public void deleteAll() { List<Category> cs = list(); for (Category c : cs) { categoryMapper.delete(c.getId()); } } @Override public void addTwo() { Category c1 = new Category(); c1.setName("短的名字"); categoryMapper.add(c1); Category c2 = new Category(); c2.setName("名字长对应字段放不下,名字长对应字段放不下,名字长对应字段放不下,名字长对应字段放不下,名字长对应字段放不下,名字长对应字段放不下,名字长对应字段放不下,名字长对应字段放不下,"); categoryMapper.add(c2); }; }
步骤 8 :

修改测试类,观察效果

修改测试类MybatisTest :注入CategoryService 对象,并调用deleteAll和addTwo方法,运行后在数据库中发现只有只有一条数据插入成功了,说明addTwo方法不是事务管理的。 如果是事务管理的,那么就应该都成功,或者都失败。
修改测试类,观察效果
package com.how2java.test; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.how2java.service.CategoryService; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class MybatisTest { @Autowired private CategoryService categoryService; @Test public void testAddTwo() { categoryService.deleteAll(); categoryService.addTwo(); } }
步骤 9 :

进行事务配置

修改applicationContext.xml,添加事务管理器和事务注解扫描器
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <context:annotation-config /> <context:component-scan base-package="com.how2java.service" /> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName"> <value>com.mysql.jdbc.Driver</value> </property> <property name="url"> <value>jdbc:mysql://localhost:3306/how2java?characterEncoding=UTF-8</value> </property> <property name="username"> <value>root</value> </property> <property name="password"> <value>admin</value> </property> </bean> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="typeAliasesPackage" value="com.how2java.pojo" /> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations" value="classpath:com/how2java/mapper/*.xml"/> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.how2java.mapper"/> </bean> <tx:annotation-driven transaction-manager="transactionManager"/> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> </beans>
步骤 10 :

使用注解方式

为addTwo方法加上事务注解
package com.how2java.service.impl; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.how2java.mapper.CategoryMapper; import com.how2java.pojo.Category; import com.how2java.service.CategoryService; @Service public class CategoryServiceImpl implements CategoryService{ @Autowired CategoryMapper categoryMapper; public List<Category> list(){ return categoryMapper.list(); } public void deleteAll() { List<Category> cs = list(); for (Category c : cs) { categoryMapper.delete(c.getId()); } } @Override @Transactional(propagation=Propagation.REQUIRED,rollbackForClassName="Exception") public void addTwo() { Category c1 = new Category(); c1.setName("短的名字"); categoryMapper.add(c1); Category c2 = new Category(); c2.setName("名字长对应字段放不下,名字长对应字段放不下,名字长对应字段放不下,名字长对应字段放不下,名字长对应字段放不下,名字长对应字段放不下,名字长对应字段放不下,名字长对应字段放不下,"); categoryMapper.add(c2); }; }
步骤 11 :

运行测试类,观察效果

运行测试类MybatisTest发现数据库里是空的。因为第二个数据插入不进去,所以第一个数据的插入也回滚了。
运行测试类,观察效果
步骤 12 :

使用XML配置方式

修改applicationContext,以支持AOP方式
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <context:annotation-config /> <context:component-scan base-package="com.how2java.service" /> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName"> <value>com.mysql.jdbc.Driver</value> </property> <property name="url"> <value>jdbc:mysql://localhost:3306/how2java?characterEncoding=UTF-8</value> </property> <property name="username"> <value>root</value> </property> <property name="password"> <value>admin</value> </property> </bean> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="typeAliasesPackage" value="com.how2java.pojo" /> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations" value="classpath:com/how2java/mapper/*.xml"/> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.how2java.mapper"/> </bean> <!-- <tx:annotation-driven transaction-manager="transactionManager"/> --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <tx:advice id="txadvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="add*" propagation="REQUIRED" rollback-for="Exception" /> <tx:method name="del*" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="edit*" propagation="REQUIRED" rollback-for="Exception" /> <tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="list*" propagation="REQUIRED" rollback-for="Exception"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="serviceMethod" expression="execution(* com.how2java.service.*.*(..))"/> <aop:advisor pointcut-ref="serviceMethod" advice-ref="txadvice"/> </aop:config> </beans>
步骤 13 :

运行测试类,观察效果

运行MybatisTest可以看到一样的事务效果,即都没有插入成功
运行测试类,观察效果
步骤 14 :

为什么不启动Web应用进行测试?

为什么不启动Web应用进行测试? 而是要用一个MybatisTest这种方式?

因为根据前面的教材,都是基于一个实体类做管理的ssm应用,不方便重现事务出问题的现象。

通过本教材的方式,也是修改Service以提供事务管理的支持,其效果也是能够运用在web应用的。


HOW2J公众号,关注后实时获知布最新的教程和优惠活动,谢谢。


问答区域    
2018-01-28 aop和事务管理的关系
老邱



站长我有一个问题,为什么这么写能够起到事务的作用,就是为什么用事务要用到aop的知识,是不是这个xml方式不用aop就没法事务管理了
<tx:advice id="txadvice" transaction-manager="transactionManager"> 
        <tx:attributes> 
            <tx:method name="add*" propagation="REQUIRED" rollback-for="Exception" /> 
            <tx:method name="del*" propagation="REQUIRED" rollback-for="Exception"/>
            <tx:method name="edit*" propagation="REQUIRED" rollback-for="Exception" />
            <tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/> 
            <tx:method name="list*" propagation="REQUIRED" rollback-for="Exception"/> 
        </tx:attributes> 
    </tx:advice> 
        
    <aop:config> 
        <aop:pointcut id="serviceMethod" expression="execution(* com.how2java.service.*.*(..))"/> 
        <aop:advisor pointcut-ref="serviceMethod" advice-ref="txadvice"/> 
    </aop:config> 

							






答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到





2017-10-19 事务无法回滚
岁末



使用注解方式用测试类能够执行回滚, 如果在service层直接调用,就无法回滚。 使用配置方式用测试类无法执行回滚, 如果在service层直接调用,无法回滚。
public void test(){
    	System.out.println("测试");
    	deleteAll();
    	addTwo();
    }
public List<Category> list(Page page)
    {
    	if(page.getStartPage()<0)
    		page.setStartPage(0);
         test();
    	return categoryMapper.list(page);
    }
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: 
### Error updating database.  Cause: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'name' at row 1
### The error may involve mapper.CategoryMapper.add-Inline
### The error occurred while setting parameters
### SQL: insert into category_ (name) values(?)
### Cause: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'name' at row 1
; SQL []; Data truncation: Data too long for column 'name' at row 1; nested exception is com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'name' at row 1
	org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:963)
	org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:842)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
	org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:827)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)


4 个答案

宅森 答案时间:2018-01-03
切入点的包名对吗

hliuece2016 答案时间:2017-12-31
你好,我是把addTwo()里的第二项的名字缩短了,就能正常执行了。你看看对你有没有什么帮助。

岁末 答案时间:2017-11-02
有的,默认InnoDB。

how2j 答案时间:2017-10-20
数据库有设置InnoDB吗




答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到





2017-08-28 我想问一下怎么扑抓这个事务异常来达到我想要做的错误提示




提问之前请登陆
关于 JAVA 框架-SSM-事务管理 的提问

尽量提供截图代码异常信息,有助于分析和解决问题。 也可进本站QQ群交流: 389538688
站长会在每个工作日早上尽量回答提问(如果有漏掉没有回答的,请进群提醒一下)
提问尽量提供完整的代码,环境描述,越是有利于问题的重现,您的问题越能更快得到解答。
对教程中代码有疑问,请提供是哪个步骤,哪一行有疑问,这样便于快速定位问题,提高问题得到解答的速度
站长是玻璃心,提问的时候请语气温柔些 kiss~
截止2017-5-19日累计提问 1638个,站长回答了 1546个
截止2017-8-15日累计提问 2788个,站长回答了 2544个

上传截图