11.Spring整合Mybatis
步骤:
-
导入相关的包
<dependencies> <!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!--mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <!--mybatis-spring 在Spring中使用Mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.6</version> </dependency> <!--spring-webmvc--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.8</version> </dependency> <!--spring-jdbc--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.5</version> </dependency> <!--AOP--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.6</version> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> </dependency> </dependencies> <!--配置Maven静态资源过滤问题--> <build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
-
编写配置文件
-
代码实现
回忆使用Mybatis
1.编写pojo实体类
@Data
public class User {
private int id;
private String name;
private String pwd;
}
2.编写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>
<typeAliases>
<package name="com.kuang.pojo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="com.kuang.mapper.UserMapper"/>
</mappers>
</configuration>
3.编写dao层Mapper接口和Mapper.xml映射文件
UserMapper
public interface UserMapper {
public List<User> selectUser();
}
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.kuang.mapper.UserMapper">
<select id="selectUser" resultType="user">
select * from mybatis.user;
</select>
</mapper>
4.测试类(此处省略了工具类,直接创建SqlSession)
public class MyTest {
@Test
public void test() throws IOException {
//读取核心配置文件通过SqlSessionFactory获取SqlSession
String resource="mybatis-config.xml";
InputStream in = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = sqlSessionFactory.openSession();
//测试
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.selectUser();
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
}
MyBatis-Spring学习
引入Spring之前需要了解mybatis-spring包中的一些重要类;
什么是MyBatis-Spring包?
Mybatis-Spring会帮助你将MyBatis代码无缝整合到Spring中
-
版本配合
-
maven加入包
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.2</version> </dependency>
-
要和Spring一起使用Mybatis,至少需要在Spring上下文中定义两样东西:一个
SqlSessionFactory
和至少一个数据映射类。-
在Mybatis-Spring中,使用
SqlSessionFactoryBean
来创建SqlSessionFactory对象基础Mybatis语法中通过SqlSessionFactoryBuilder来创建SqlSessionFactory,Mybatis-Spring中则是通过SqlSessionFactoryBean来创建
<!--3.配置SqlSessionFactory,需传入dataSource--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--传入dataSource--> <property name="dataSource" ref="dataSource"/> <!--beans.xml关联MyBatis的mybatis-config.xml文件--> <property name="configLocation" value="mybatis-config.xml"/> <!--beans.xml配置mybatis-config.xml中的Mapper注册--> <property name="mapperLocations" value="classpath:com/kuang/dao/*.xml"/> </bean>
-
SqlSessionFactory需要配置一个DataSource,可以是任意数据源,它的配置方法和其他Spring数据库连接是一样的。
-
一个常用的属性是
configLocation
,用来制定MyBatis的XML配置文件路径。它在修改MyBatis的基础配置时非常有用,基础配置通常指的是
<setting>
和<typeAliases>
-
-
利用SqlSessionFactory,创建SqlSession
获得SqlSession以后,就可以使用它来执行映射了的语句,提交或者回滚连接。
SqlSessionTemplate
是Mybatis-Spring的核心。作为SqlSession的一个实现,可以无缝代替代码中的SqlSession。- 模板可以参与到Spring的事务管理中,并且由于其是线程安全的,可以供多个映射器类使用。
可以使用SqlSessionFactory作为构造方法的参数,来创建SqlSessionTemplate对象
<!--4.注册sqlSessionTemplate,相当于SqlSession,关联SqlSessionFactory--> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <!--利用构造器注入--> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean>
-
现在这个bean就可以直接注入到接口实现类的bean中;
先创建接口实现类
然后注入SqlSessionTemplate,具体见下面整合实践一
-
11.1整合实现一(推荐):
Spring整合Mybatis核心:
- 在Spring的配置文件beans.xml中,配置Mybatis的核心配置文件mybatis.xml
- 在Spring的配置文件beans.xml中,干掉Mybatis手动获取Resource并利用SqlSessionFactory生成SqlSession的过程
- 增加了一个新的实现类UserMapperImpl
步骤:
-
引入Spring配置文件beans.xml
-
配置数据源替换mybatis的数据源dataSource(Mybatis在mybatis-config.xml中environment中配置了数据源)
(一旦在beans.xml中配置了,原mybatis-config.xml中设置可删除)
<!--2.配置数据源:数据源有非常多,可以使用第三方的,也可以使用Spring的--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </bean>
-
配置SqlSessionFactory,beans.xml关联MyBatis的mybatis-config.xml文件,beans.xml配置mybatis-config.xml中的Mapper注册)
<!--3.配置SqlSessionFactory,需传入dataSource--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--传入dataSource--> <property name="dataSource" ref="dataSource"/> <!--beans.xml关联MyBatis的mybatis-config.xml文件--> <property name="configLocation" value="mybatis-config.xml"/> <!--beans.xml配置mybatis-config.xml中的Mapper注册--> <property name="mapperLocations" value="classpath:com/kuang/dao/*.xml"/> </bean>
-
注册sqlSessionTemplate(相当于SqlSession),关联sqlSessionFactory
<!--4.注册sqlSessionTemplate,相当于SqlSession,关联SqlSessionFactory--> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <!--利用构造器注入--> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean>
-
【重点】增加dao接口的实现类;私有化sqlSessionTemplate,采用构造方法注入,sql操作封装
public class UserMapperImpl implements UserMapper{ //sqlSession不用我们自己创建了,Spring来管理 private SqlSessionTemplate sqlSession; public UserMapperImpl(SqlSessionTemplate sqlSession) { this.sqlSession = sqlSession; } //sql操作 @Override public List<User> selectUser() { UserMapper mapper = sqlSession.getMapper(UserMapper.class); return mapper.selectUser(); } }
实现类注册bean实现
<!--5.增加dao接口的实现类;私有化sqlSessionTemplate,实现类注册bean--> <bean id="userDao" class="com.kuang.dao.UserMapperImpl"> <constructor-arg name="sqlSession" ref="sqlSession"/> </bean>
-
测试,结果成功输出
完整beans.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--2.配置数据源:数据源有非常多,可以使用第三方的,也可以使用Spring的-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!--3.配置SqlSessionFactory,需传入dataSource-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--传入dataSource-->
<property name="dataSource" ref="dataSource"/>
<!--beans.xml关联MyBatis的mybatis-config.xml文件-->
<property name="configLocation" value="mybatis-config.xml"/>
<!--beans.xml配置mybatis-config.xml中的Mapper注册-->
<property name="mapperLocations" value="classpath:com/kuang/dao/*.xml"/>
</bean>
<!--4.注册sqlSessionTemplate,相当于SqlSession,关联SqlSessionFactory-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--利用构造器注入-->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
<!--5.增加dao接口的实现类;私有化sqlSessionTemplate,实现类注册bean-->
<bean id="userDao" class="com.kuang.dao.UserMapperImpl">
<constructor-arg name="sqlSession" ref="sqlSession"/>
</bean>
</beans>
完整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>
<!--Spring整合Mybatis后,mybatis-config.xml中只保留settings和typeAliases,其他的配置都在beans.xml中配置-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<typeAliases>
<package name="com.kuang.pojo"/>
</typeAliases>
</configuration>
我们发现,mybatis-config.xml配置文件的状态,都可以被Spring的beans.xml整合
易错:xml文件中如果出现中文注释,可能会出错
11.2整合实现二
mybatis-spring1.2.3版以上才有这个
官方文档截图:
-
dao继承Support类,直接利用getSession()获得,然后直接注入SqlSessionFactory。
-
比起方式一,不需要管理SqlSessionTemplate,而且对事务的支持更加友好,可跟踪源码查看
测试:
-
将我们上面写的UserMapperImpl修改一下
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{ //此时不再需要私有sqlSession变量 //sql操作 public List<User> selectUser() { UserMapper mapper = getSqlSession().getMapper(UserMapper.class); return mapper.selectUser(); } }
-
修改bean的配置
<bean id="userDao" class="com.kuang.dao.UserMapperImpl"> <property name="sqlSessionFactory" ref="sqlSessionFactory"/> </bean>
给UserMapperImpl中的SqlSessionDaoSuport传入sqlSessionFactory参数,采用set注入
-
测试
@Test public void test2(){ ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); UserMapper mapper = (UserMapper) context.getBean("userDao"); List<User> userList = mapper.selectUser(); for (User user : userList) { System.out.println(user); } }
总结:
- Mybatis整合到spring中以后,可以完全不要mybatis的配置,其原有的所有配置都可以在Spring中的beans.xml中配置;
- 除了这些方式可以实现整合之外,我们还可以使用注解来实现,这个等我们后面学习SpringBoot的时候,还会测试整合!
Spring整合Mybatis时,配置文件分类与引用:
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>
<!--Spring整合Mybatis后,mybatis-config.xml中只保留settings和typeAliases,其他的配置都在beans.xml中配置-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<typeAliases>
<package name="com.kuang.pojo"/>
</typeAliases>
</configuration>
spring-dao.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--2.配置数据源:数据源有非常多,可以使用第三方的,也可以使用Spring的-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!--3.配置SqlSessionFactory,需传入dataSource-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--传入dataSource-->
<property name="dataSource" ref="dataSource"/>
<!--beans.xml关联MyBatis的mybatis-config.xml文件-->
<property name="configLocation" value="mybatis-config.xml"/>
<!--beans.xml配置mybatis-config.xml中的Mapper注册-->
<property name="mapperLocations" value="classpath:com/kuang/dao/*.xml"/>
</bean>
<!--4.注册sqlSessionTemplate,相当于SqlSession,关联SqlSessionFactory-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--利用构造器注入-->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
</beans>
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--引入spring-dao.xml配置文件-->
<import resource="spring-dao.xml"/>
<!--5.增加dao接口的实现类;私有化sqlSessionTemplate,实现类注册bean-->
<bean id="userDao" class="com.kuang.dao.UserMapperImpl">
<constructor-arg name="sqlSession" ref="sqlSession"/>
</bean>
</beans>
12.Spring中为Mybatis配置声明式事务
- Spring中事务可以分为声明式事务和编程式事务
- 编程式事务:代码中显示开启和关闭事务
- 声明式事务:可以采用AOP横切的方式为所有方法或者特定方法添加事务
12.1事务测试
-
将上面Mybatis在Spring中的实现拷入新的项目中
-
在之前的案例中,我们给userMapper.java接口新增两个方法,删除和增加用户
//添加一个用户 int addUser(User user); //删除一个用户 int deleteUser(int id);
UserMapper.xml文件,我们故意把deletes写错
<insert id="addUser" parameterType="user"> insert into `user`(id,name,pwd) values (#{id},#{name},#{pwd}) </insert> <delete id="deleteUser" parameterType="_int"> deletes from user where id=#{id}; </delete>
改写实现类UserMapperImpl.java
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{ //此时不再需要私有sqlSession变量 //在这个方法里面测试事务 public List<User> selectUser() { User user = new User(8, "xiaoming", "xiaoming123"); UserMapper mapper = getSqlSession().getMapper(UserMapper.class); mapper.addUser(user); //添加,应该添加事务 mapper.deleteUser(7); //删除 return mapper.selectUser(); } //新增 public int addUser(User user){ return getSqlSession().getMapper(UserMapper.class).addUser(user); } //删除 public int deleteUser(int id){ return getSqlSession().getMapper(UserMapper.class).deleteUser(id); } }
-
测试,不变
@Test public void test2(){ ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); UserMapper mapper = (UserMapper) context.getBean("userDao"); List<User> userList = mapper.selectUser(); for (User user : userList) { System.out.println(user); } }
报错:sql异常,delete写错了
结果:插入成功
没有进行事务的管理;我们想让他们都成功才算成功,有一个失败,就都失败,我们就应该需要事务!
以前我们都需要自己手动管理事务,十分麻烦!
但是Spring给我们提供了事务管理,我们只需要配置即可。
12.2Spring中的事务管理
- 在Spring中采用AOP为所有方法或者特定方法横切事务
- Spring在不同的事务管理API之上定义了一个抽象层,使得开发人员不必了解底层的事务管理API就可以使用Spring的事务管理机制
- Spring支持编程式事务和声明式事务管理
- 编程式事务管理:事务管理代码嵌入业务方法,必须在每个事物操作业务逻辑中包含额外的事物管理代码;
- 声明式事务管理:更好用,将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。将事务管理作为横切关注点,通过AOP方法模块化,Spring中通过Spring AOP框架支持声明式事务管理。
-
在Spring配置中管理事务,需要在beans.xml中导入头文件的约束:tx
xmlns:tx="http://www.springframework.org/schema/tx" http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd
-
在beans.xml中,配置事务管理器,得到Spring提供的事务管理器对象
- 无论使用Spring的哪种事务管理策略(编程式或者声明式),事务管理器都是必须的
- 就是Spring的核心事务管理抽象,管理封装了一组独立于技术的方法
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>
-
采用AOP横切,将Spring的事务横切到所有方法或者特定方法
-
配置事务通知
<!--配置事物通知--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!--配置哪些方法使用什么样的事务,配置事务的传播特性--> <tx:method name="add" propagation="REQUIRED"/> <tx:method name="delete" propagation="REQUIRED"/> <tx:method name="update" propagation="REQUIRED"/> <tx:method name="query" propagation="REQUIRED"/> <tx:method name="get" read-only="true"/> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice>
Spring事务的传播特性:
事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。Spring支持7中事务传播行为:
- required 没有事务就新建事务;已经存在一个事务,加入该事务
- supports 有事务就支持,没有就没有
- mandatory 有事务就支持,没有就抛异常
- required_new 没有事务就新建事务,有事务把当前事务挂起
- not_supported 非事务方式执行,有事务把当前事务挂起
- never 不支持事务,有事务就抛出异常
- nested 存在事务,嵌套事务;否则新建事务
Spring默认的事务传播行为是required,适用于绝大多数情况
-
配置AOP
导入aop的头文件
<aop:config> <aop:pointcut id="txPointcut" expression="execution(* com.kuang.dao.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/> </aop:config>
-
测试:
删除刚才插入的数据,再次测试;
此时我们发现所有方法都横切进入了事务,所有sql操作都成功才成功,否则失败。
为什么需要配置声明式事务?
- 如果不配置,就需要我们手动提交控制事务;
- 事务在项目开发过程中非常重要,涉及到数据的一致性问题,不容马虎!