文章目录
六、MyBatis-Spring
参考官网地址http://mybatis.org/spring/zh/index.html
6.1、整合MyBatis所需的maven依赖
- mybatis
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
- mysql-connector-java
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
- mybatis-spring整合包
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
- spring相关
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.14</version>
</dependency>
<!-- spring操作数据库的依赖:spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.15</version>
</dependency>
- aspectJ AOP 织入器
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
- 其他
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
6.2、SqlSession
6.2.1、SqlSessionFactoryBean
在基础的 MyBatis 用法中,是通过 SqlSessionFactoryBuilder
来创建 SqlSessionFactory
的。而在 MyBatis-Spring 中,则使用 SqlSessionFactoryBean
来创建
配置spring-dao.xml
要创建工厂 bean,将下面的代码放到 Spring 的 XML 配置文件中:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
需要注意的是 SqlSessionFactoryBean
实现了 Spring 的 FactoryBean
接口(参见 Spring 官方文档 3.8 节 通过工厂 bean 自定义实例化逻辑 )。 这意味着由 Spring 最终创建的 bean 并不是 SqlSessionFactoryBean
本身,而是工厂类(SqlSessionFactoryBean
)的 getObject() 方法的返回结果。这种情况下,Spring 将会在应用启动时为你创建 SqlSessionFactory
,并使用 sqlSessionFactory
这个名字存储起来。
等效的 Java 代码如下:
@Configuration
public class MyBatisConfig {
@Bean
public SqlSessionFactory sqlSessionFactory() {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource());
return factoryBean.getObject();
}
}
SqlSessionFactoryBean属性
- dataSource用于 JDBC
<property name="dataSource" ref="dataSource" />
- configLocation指定 MyBatis 的 XML 配置文件路径
<property name="configLocation" value="classpath:mybatis-config.xml"/>
- mapperLocations指定 MyBatis 的映射器 XML 配置文件的位置(可接受多个资源位置)
<property name="mapperLocations" value="classpath*:sample/config/mappers/**/*.xml" />
- databaseIdProvider用于使用多个数据库,如:
<bean id="databaseIdProvider" class="org.apache.ibatis.mapping.VendorDatabaseIdProvider">
<property name="properties">
<props>
<prop key="SQL Server">sqlserver</prop>
<prop key="DB2">db2</prop>
<prop key="Oracle">oracle</prop>
<prop key="MySQL">mysql</prop>
</props>
</property>
</bean>
6.2.2、SqlSession的使用
在使用 MyBatis-Spring 之后,你不再需要直接使用 SqlSessionFactory
了,因为你的 bean 可以被注入一个线程安全的 SqlSession
,它能基于 Spring 的事务配置来自动提交、回滚、关闭 session。
SqlSessionTemplate
-
线程安全的,可以被多个 DAO 或映射器所共享使用。
-
当调用 SQL 方法时(包括由
getMapper()
方法返回的映射器中的方法),SqlSessionTemplate
将会保证使用的SqlSession
与当前 Spring 的事务相关。 此外,它管理 session 的生命周期,包含必要的关闭、提交或回滚操作。另外,它也负责将 MyBatis 的异常翻译成 Spring 中DataAccessExceptions。 -
需要总是用
SqlSessionTemplate
来替换 MyBatis 默认的DefaultSqlSession
实现。在同一应用程序中的不同类之间混杂使用可能会引起数据一致性的问题。
可以使用 SqlSessionFactory
作为构造方法的参数来创建 SqlSessionTemplate
对象。
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
@Configuration
public class MyBatisConfig {
@Bean
public SqlSessionTemplate sqlSession() throws Exception {
return new SqlSessionTemplate(sqlSessionFactory());
}
}
现在,这个 bean 就可以直接注入到你的 DAO bean 中了。你需要在你的 bean 中添加一个 SqlSession 属性,就像下面这样:
public class UserDaoImpl implements UserDao {
private SqlSession sqlSession;
public void setSqlSession(SqlSession sqlSession) {
this.sqlSession = sqlSession;
}
public User getUser(String userId) {
return sqlSession.selectOne("org.mybatis.spring.sample.mapper.UserMapper.getUser", userId);
}
}
按下面这样,注入 SqlSessionTemplate
:
<bean id="userDao" class="org.mybatis.spring.sample.dao.UserDaoImpl">
<property name="sqlSession" ref="sqlSession" />
</bean>
SqlSessionTemplate
还有一个接收 ExecutorType
参数的构造方法。这允许你使用如下 Spring 配置来批量创建对象,例如批量创建一些 SqlSession:
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
<constructor-arg index="1" value="BATCH" />
</bean>
@Configuration
public class MyBatisConfig {
@Bean
public SqlSessionTemplate sqlSession() throws Exception {
return new SqlSessionTemplate(sqlSessionFactory(), ExecutorType.BATCH);
}
}
现在所有的映射语句可以进行批量操作了,可以在 DAO 中编写如下的代码
public class UserService {
private final SqlSession sqlSession;
public UserService(SqlSession sqlSession) {
this.sqlSession = sqlSession;
}
public void insertUsers(List<User> users) {
for (User user : users) {
sqlSession.insert("org.mybatis.spring.sample.mapper.UserMapper.insertUser", user);
}
}
}
注意,只需要在希望语句执行的方法与 SqlSessionTemplate
中的默认设置不同时使用这种配置。
这种配置的弊端在于,当调用这个方法时,不能存在使用不同 ExecutorType
的进行中的事务。要么确保对不同 ExecutorType
的 SqlSessionTemplate
的调用处在不同的事务中,要么完全不使用事务。
SqlSessionDaoSupport
SqlSessionDaoSupport
是一个抽象的支持类,用来为你提供 SqlSession
。调用 getSqlSession()
方法你会得到一个 SqlSessionTemplate
,之后可以用于执行 SQL 方法,就像下面这样:
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
public User getUser(String userId) {
return getSqlSession().selectOne("org.mybatis.spring.sample.mapper.UserMapper.getUser", userId);
}
}
在这个类里面,通常更倾向于使用 MapperFactoryBean
,因为它不需要额外的代码。但是,如果你需要在 DAO 中做其它非 MyBatis 的工作或需要一个非抽象的实现类,那么这个类就很有用了。
SqlSessionDaoSupport
需要通过属性设置一个 sqlSessionFactory
或 SqlSessionTemplate
。如果两个属性都被设置了,那么 SqlSessionFactory
将被忽略。
假设类 UserMapperImpl
是 SqlSessionDaoSupport
的子类,可以编写如下的 Spring 配置来执行设置:
<bean id="userDao" class="org.mybatis.spring.sample.dao.UserDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
整体测试样例
1、编写pojo类
package com.rui.pojo;
import lombok.Data;
@Data
public class User {
private int id;
private String name;
private String pwd;
}
2、编写UserMapper接口
package com.rui.mapper;
import com.rui.pojo.User;
import java.util.List;
public interface UserMapper {
public List<User> selectUser();
}
3、编写UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.rui.mapper.UserMapper">
<select id="selectUser" resultType="user">
select * from user;
</select>
</mapper>
4、创建db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true
username=root
password=123456
5、编写mybatis-config.xml配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration-核心配置文件-->
<configuration>
<!-- 引入外部配置文件 -->
<properties resource="db.properties"/>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!-- 类型别名 -->
<typeAliases>
<package name="com.rui.pojo"/>
<!-- 使用package扫描文件夹下的类,默认首字母小写 -->
</typeAliases>
<environments default="development">
<environment id="development">
<!-- 事务管理器 -->
<transactionManager type="JDBC"/>
<!-- 数据源 -->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<!-- xml中&需要转义& MySQL 8.0 配置时区 serverTimezone=GMT -->
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="com.rui.mapper.UserMapper"/>
</mappers>
</configuration>
6、编写Spring-dao.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- DataSource:使用Spring的数据源配置Mybatis的配置 c3p0 dbcp
我们这里使用Spring提供给的JDBC
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!-- sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 绑定mybatis的配置文件 -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- <property name="mapperLocations" value="classpath*:com/rui/mapper/*.xml"/> -->
<!-- 1.如果Mapper.xml与Mapper.class在同一个包下且同名,spring扫描Mapper.class的同时会自动扫描同名的Mapper.xml并装配到Mapper.class。 -->
<!-- 2.如果Mapper.xml与Mapper.class不在同一个包下或者不同名,就必须使用配置mapperLocations指定mapper.xml的位置。 -->
</bean>
<!-- SqlSessionTemplate -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!-- 使用构造器注入方法,因为没有set方法, -->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
</beans>
7、编写SqlSessionTemplate所需的UserMapperImpl1类
package com.rui.mapper;
import com.rui.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl implements UserMapper{
//Spring整合Mybatis将操作整入到类里面
//我们的所有操作都是用sqlSession来执行-->SqlSessionTemplate(私有化sqlSessionTemplate)
private SqlSessionTemplate sqlSessionTemplate;
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSessionTemplate = sqlSessionTemplate;
}
@Override
public List<User> selectUser() {
UserMapper mapper = sqlSessionTemplate.getMapper(UserMapper.class);
return mapper.selectUser();
}
}
8、编写applicationContext.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 导入spring-dao.xml配置文件>
<import resource="spring-dao.xml"/>
<bean id="usermapper" class="com.rui.mapper.UserMapperImpl">
<property name="sqlSessionTemplate" ref="sqlSession"/>
</bean>
<bean id="usermapper2" class="com.rui.mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
</beans>
9.编写测试类代码
import com.rui.mapper.UserMapper;
import com.rui.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
public class MyTest {
public static void main(String[] args){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//SqlSessionTemplate
UserMapper mapper = context.getBean("usermapper", UserMapper.class);
//SqlSessionDaoSupport
UserMapper mapper2 = context.getBean("usermapper2", UserMapper.class);
for (User user : mapper.selectUser()) {
System.out.println(user);
}
System.out.println("===================");
for (User user : mapper2.selectUser()) {
System.out.println(user);
}
}
}
6.3、事务管理
-
在 Spring 的配置文件中创建一个
DataSourceTransactionManager
对象: -
支持
@Transactional
注解和 AOP 风格的配置。在事务处理期间,一个单独的SqlSession
对象将会被创建和使用。当事务完成时,这个 session 会以合适的方式提交或回滚。 -
在你的 DAO 类中就不需要额外的代码
标准配置
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource" />
</bean>
@Configuration
public class DataSourceConfig {
@Bean
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
事务管理器指定的 DataSource 必须和用来创建 SqlSessionFactoryBean`的是同一个数据源
Spring在不同的事务管理API之上定义了一个抽象层,使得开发人员不必了解底层的事务管理API就可以使用Spring的事务管理机制。Spring支持编程式事务管理和声明式的事务管理。
使用Spring管理事务,注意头文件的约束导入 : tx
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
spring事务传播特性:
事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。spring支持7种事务传播行为:
- propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。
- propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
- propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
- propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
- propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
- propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作
Spring 默认的事务传播行为是 PROPAGATION_REQUIRED,它适合于绝大多数的情况。
声明式事务:AOP
编程式事务:需要在代码中,进行事务的管理(不推荐)
编程式事务管理
- 将事务管理代码嵌到业务方法中来控制事务的提交和回滚
- 缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码
声明式事务管理
- 一般情况下比编程式事务好用。
- 将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
- 将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。
测试配置声明式事务样例
1、编写UserMapper实体类
package com.rui.mapper;
import com.rui.pojo.User;
import java.util.List;
public interface UserMapper {
public List<User> selectUser();
//事务
//添加一个用户
public int addUser(User user);
//删除一个用户
public int deleteUser(int id);
}
2、编写UserMapper.xml(故意写错delete成deletes,删除和增加两事件同时进行,查看结果)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.rui.mapper.UserMapper">
<select id="selectUser" resultType="user">
select * from user;
</select>
<insert id="addUser" parameterType="User">
insert into mybatis.user (id,`name`,pwd) values (#{id},#{name},#{pwd});
</insert>
<delete id="deleteUser" parameterType="int">
deletes from user where id=#{id};
</delete>
</mapper>
3、使用SqlSessionDaoSupport编写实现类UserMapperImpl(测试的是selectUser()方法,其中包含了添加用户,和一个故意写错的删除用户操作)
package com.rui.mapper;
import com.rui.pojo.User;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{
@Override
public List<User> selectUser() {
User user = new User(6, "xiaozhang", "155246");
this.addUser(user);
this.deleteUser(6);
//getSqlSession()得到sqlSessionTemplate
return getSqlSession().getMapper(UserMapper.class).selectUser();
}
@Override
public int addUser(User user) {
return getSqlSession().getMapper(UserMapper.class).addUser(user);
}
@Override
public int deleteUser(int id) {
return getSqlSession().getMapper(UserMapper.class).deleteUser(id);
}
}
4、配置mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<typeAliases>
<package name="com.rui.pojo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="com.rui.mapper.UserMapper"/>
</mappers>
</configuration>
5、配置spring-dao.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- DataSource:使用Spring的数据源配置Mybatis的配置 c3p0 dbcp
我们这里使用Spring提供给的JDBC
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!-- sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 绑定mybatis的配置文件 -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- <property name="mapperLocations" value="classpath*:com/rui/mapper/*.xml"/> -->
<!-- 1.如果Mapper.xml与Mapper.class在同一个包下且同名,spring扫描Mapper.class的同时会自动扫描同名的Mapper.xml并装配到Mapper.class。 -->
<!-- 2.如果Mapper.xml与Mapper.class不在同一个包下或者不同名,就必须使用配置mapperLocations指定mapper.xml的位置。 -->
</bean>
<!-- SqlSessionTemplate -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!-- 使用构造器注入方法,因为没有set方法, -->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
<!-- 配置声明式事务 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource" />
</bean>
<!-- 结合AOP实现事务的植入 -->
<!-- 1.配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 给那些方法配置事务 -->
<!-- 配置事务的传播:new propagation-->
<tx:attributes>
<!-- 配置哪些方法使用什么样的事务,配置事务的传播特性 -->
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 2.配置事务切入 -->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.rui.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
</beans>
6、配置applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<import resource="spring-dao.xml"/>
<bean id="usermapper" class="com.rui.mapper.UserMapperImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
</beans>
7、编写测试类
import com.rui.mapper.UserMapper;
import com.rui.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Mytest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper mapper = context.getBean("usermapper", UserMapper.class);
for (User user : mapper.selectUser()) {
System.out.println(user);
}
}
}
8、测试结果为添加用户和删除用户均未成功,事务回滚,满足需求!