mybatis和spring的整合是mybatis开发团队主动开发一套集成框架,方便与spring整合,包括后面的mybatis与springboot整合!
本章将会以简略的步骤告诉你如何安装和配置 MyBatis-Spring,并构建一个简单的具备事务管理功能的数据访问应用程序。
1、什么是 MyBatis-Spring?
MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。它将允许 MyBatis 参与到 Spring 的事务管理之中,创建映射器 mapper 和 SqlSession 并注入到 bean 中,以及将 Mybatis 的异常转换为 Spring 的 DataAccessException。最终,可以做到应用代码不依赖于 MyBatis,Spring 或 MyBatis-Spring。
2、MyBatis-Spring 需要以下版本:
MyBatis-Spring | MyBatis | Spring Framework | Spring Batch | Java |
---|---|---|---|---|
2.0 | 3.5+ | 5.0+ | 4.0+ | Java 8+ |
1.3 | 3.4+ | 3.2.2+ | 2.1+ | Java 6+ |
3、安装依赖
要使用 MyBatis-Spring 模块,只需要在类路径下包含 mybatis-spring-2.0.6.jar
文件和相关依赖即可。
本文采用 Maven 作为构建工具,仅需要在 pom.xml 中加入以下代码即可:
<!-- mybatis 整合 spring 的依赖包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!-- mybatis 依赖包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!-- spring jdbc 配置数据源-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.4.5</version>
</dependency>
<!-- mysql 连接驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
4、使用XML方式集成spring
集成思想一定要清晰,大致思路如下:
1、将mybatis核心的对象构建起来(首先mybatis需要的东西都要有),目的就是注册进spring的IOC中。
2、分布走,mybatis需要的插件,比如数据库连接等。然后再构建SqlSessionFactory 等。
3、核心注册进去后,mybatis的功能要实现,把xml、接口位置等参数注册进相对于的对象中,比如:扫描的xml位置,扫描的接口包等。
项目的整体代码结构:
1、构建SqlSessionFactory
要和 Spring 一起使用 MyBatis,需要在 Spring 应用上下文中定义至少两样东西:一个 SqlSessionFactory
和至少一个数据映射器类。
在 MyBatis-Spring 中,可使用 SqlSessionFactoryBean
来创建 SqlSessionFactory
。要配置这个工厂 bean,只需要把下面代码放在 Spring 的 XML 配置文件中:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
注意:SqlSessionFactory
需要一个 DataSource
(数据源)。这可以是任意的 DataSource
,只需要和配置其它 Spring 数据库连接一样配置它就可以了。
2、构建UserInfoMapper 接口
假设你定义了一个如下的 UserInfoMapper 接口:
public interface UserInfoMapper {
// 采用注解的方式 编写sql。Map<String, Object>可以修改为UserInfoVO,mybatis自动识别
// 这种方式,在mybatis的配置文件中只需要引入 该接口即可。
@Select("select user_code AS userCode, url, user_name AS userName, password FROM user_config WHERE user_code = #{userCode}")
Map<String, Object> getUserConfig(@Param("userCode") String userCode);
}
那么可以通过 MapperFactoryBean
将接口加入到 Spring 中:
<!-- 配置 userMapper 接口 -->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.fagejiang.mapper.UserInfoMapper"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
需要注意的是:所指定的映射器类必须是一个接口,而不是具体的实现类。在这个示例中,通过注解来指定 SQL 语句,但是也可以使用 MyBatis 映射器的 XML 配置文件。
配置好之后,你就可以像 Spring 中普通的 bean 注入方法那样,将映射器注入到你的业务或服务对象中。MapperFactoryBean
将会负责 SqlSession
的创建和关闭。如果使用了 Spring 的事务功能,那么当事务完成时,session 将会被提交或回滚。最终任何异常都会被转换成 Spring 的 DataAccessException
异常。
要调用 MyBatis 的数据方法,只需一行代码:
@Resource
UserInfoMapper userInfoMapper;
3、配置事务
一个使用 MyBatis-Spring 的其中一个主要原因是它允许 MyBatis 参与到 Spring 的事务管理中。而不是给 MyBatis 创建一个新的专用事务管理器,MyBatis-Spring 借助了 Spring 中的 DataSourceTransactionManager
来实现事务管理。
一旦配置好了 Spring 的事务管理器,你就可以在 Spring 中按你平时的方式来配置事务。并且支持 @Transactional
注解和 AOP 风格的配置。在事务处理期间,一个单独的 SqlSession
对象将会被创建和使用。当事务完成时,这个 session 会以合适的方式提交或回滚。
事务配置好了以后,MyBatis-Spring 将会透明地管理事务。这样在你的 DAO 类中就不需要额外的代码了。
要开启 Spring 的事务处理功能,在 Spring 的配置文件中创建一个 DataSourceTransactionManager
对象:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource" />
</bean>
4、配置sqlSession
在 MyBatis 中,你可以使用 SqlSessionFactory
来创建 SqlSession
。一旦你获得一个 session 之后,你可以使用它来执行映射了的语句,提交或回滚连接,最后,当不再需要它的时候,你可以关闭 session。使用 MyBatis-Spring 之后,你不再需要直接使用 SqlSessionFactory
了,因为你的 bean 可以被注入一个线程安全的 SqlSession
,它能基于 Spring 的事务配置来自动提交、回滚、关闭 session。
SqlSessionTemplate
是 MyBatis-Spring 的核心。作为 SqlSession
的一个实现,这意味着可以使用它无缝代替你代码中已经在使用的 SqlSession
。SqlSessionTemplate
是线程安全的,可以被多个 DAO 或映射器所共享使用。
更多可参考官方文档
可以使用 SqlSessionFactory 作为构造方法的参数来创建 SqlSessionTemplate 对象。
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
</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>
5、注入映射器
不需要一个个地注册你的所有映射器。你可以让 MyBatis-Spring 对类路径进行扫描来发现它们。
使用xml的方式来发现映射器:
-
使用
<mybatis:scan/>
元素
<mybatis:scan base-package="com.fagejiang.mapper"/>
6、完整的spring.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:context="http://www.springframework.org/schema/context"
xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">
<!-- 导入外部的资源文件 -->
<context:property-placeholder location="classpath:mysql.properties"/>
<!-- 设置mybatis 别名包 -->
<mybatis:scan base-package="com.fagejiang.mapper"/>
<!-- 配置数据库连接池:https://blog.csdn.net/lanwp5302/article/details/106461908 -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<!--<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" /> mysql8 -->
<property name="jdbcUrl" value="${mysql.url}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="${mysql.password}"/>
<!-- maximumPoolSize 默认 10 -->
<property name="maximumPoolSize" value="20"/>
<!-- minimumIdle 默认 等于 maximumPoolSize -->
<!--<property name="minimumIdle" value="5"/>-->
<property name="connectionTestQuery" value="SELECT 1"/>
</bean>
<!-- 数据库类型 -->
<bean id="databaseIdProvider" class="org.apache.ibatis.mapping.VendorDatabaseIdProvider">
<property name="properties">
<props>
<prop key="MySQL">mysql</prop>
</props>
</property>
</bean>
<!-- 配置mybatis 核心的 sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 配置 数据库源 属性 -->
<property name="dataSource" ref="dataSource"/>
<!-- 配置扫描的xml路径 -->
<property name="mapperLocations" value="classpath*:mappers/*.xml"/>
<!-- 配置数据库类型 -->
<property name="databaseIdProvider" ref="databaseIdProvider"/>
<!-- 自 1.3.0 版本开始,新增的 configuration 属性能够在没有对应的 MyBatis XML 配置文件的情况下,直接设置 Configuration 实例。-->
<property name="configuration">
<bean class="org.apache.ibatis.session.Configuration">
<property name="mapUnderscoreToCamelCase" value="true"/>
</bean>
</property>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource"/>
</bean>
<!-- 配置 userMapper 接口 -->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.fagejiang.mapper.UserInfoMapper"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
</beans>
7、测试
1、实体类:
public class UserInfoVO implements Serializable {
/**
*
*/
private static final long serialVersionUID = 2593256431070278531L;
private String userCode;
private String url;
private String userName;
private String password;
... 省略 setter getter
}
2、mapper接口
public interface UserInfoMapper {
// 采用注解的方式 编写sql。Map<String, Object>可以修改为UserInfoVO,mybatis自动识别
// 这种方式,在mybatis的配置文件中只需要引入 该接口即可。
@Select("select user_code AS userCode, url, user_name AS userName, password FROM user_config WHERE user_code = #{userCode}")
Map<String, Object> getUserConfig(@Param("userCode") String userCode);
// 采用 XML的方式编写动态sql,该方式必须在配置文件中引入XML,接口不必引入,
// XML中的namespace 本身指定的就是接口,mybatis内部自动会处理
UserInfoVO getUserConfig2(@Param("userCode") String userCode);
}
3、数据库
CREATE TABLE `user_config` (
`user_code` varchar(30) NOT NULL,
`url` varchar(200) NOT NULL,
`user_name` varchar(60) NOT NULL,
`password` varchar(60) DEFAULT NULL,
PRIMARY KEY (`user_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `zswz`.`user_config`(`user_code`, `url`, `user_name`, `password`) VALUES ('test', 'jdbc:mysql://192.168.0.100:13306/zswz', 'root', 'baian2020mql');
数据库配置文件mysql.properties
mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://192.168.0.100:13306/zswz?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&tinyInt1isBit=false&useSSL=false
mysql.username=root
mysql.password=root
4、测试类
@Slf4j
public class TestMybatisByXml {
@Test
public void testTestMybatisByXml() {
final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
final String[] definitionNames = context.getBeanDefinitionNames();
System.out.println(" definitionNames:");
Arrays.stream(definitionNames).forEach(System.out::println);
final UserInfoMapper userMapper = context.getBean("userMapper", UserInfoMapper.class);
final Map<String, Object> map = userMapper.getUserConfig("test");
System.out.println("\nmap = " + map);
final UserInfoVO userInfoVO = userMapper.getUserConfig2("test");
System.out.println("userInfoVO = " + userInfoVO);
final UserInfoMapperNoXml infoMapperNoXml = context.getBean("userInfoMapperNoXml", UserInfoMapperNoXml.class);
final Map<String, Object> test = infoMapperNoXml.getUserConfig("test");
System.out.println("test = " + test);
}
}
运行结果:
5、使用注解的方式
思想和xml一直,故不多bb
1、构建SqlSessionFactory
/**
* 配置数据源
* @return DataSource
*/
@Bean
public DataSource dataSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl("jdbc:mysql://192.168.0.100:13306/zswz?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&tinyInt1isBit=false&useSSL=false\n");
dataSource.setUsername("root");
dataSource.setPassword("baian2020mql");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
return dataSource;
}
/**
* 解析 xml的 工具方法,借钱springboot的mybatis.mapper-locations注入的方法, 源码复制的,寻找源码方法见最下面
* @return Resource
*/
public Resource[] resolveMapperLocations() {
ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
List<Resource> resources = new ArrayList<Resource>();
Resource[] mappers = new Resource[0];
try {
mappers = resourceResolver.getResources("mappers/*.xml");
} catch (IOException e) {
e.printStackTrace();
}
resources.addAll(Arrays.asList(mappers));
return resources.toArray(new Resource[resources.size()]);
}
/**
* 配置 SqlSessionFactory ,注入 数据源,映射的xml等信息
* @return
* @throws Exception
*/
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean.setMapperLocations(resolveMapperLocations());
Properties properties = new Properties();
properties.setProperty("MySQL", "mysql");
final VendorDatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
databaseIdProvider.setProperties(properties);
factoryBean.setDatabaseIdProvider(databaseIdProvider);
return factoryBean.getObject();
}
2、构建UserInfoMapper 接口
@MapperScan(basePackages = "com.fagejiang.mapper")
public class MybatisConfig {}
3、配置事务
@Bean
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
4、配置sqlSession
@Bean
public SqlSessionTemplate sqlSession() throws Exception {
return new SqlSessionTemplate(sqlSessionFactory(), ExecutorType.BATCH);
}
5、注入映射器
见 SqlSessionFactory 方法
6、spring启动类
@Configuration
@ComponentScan(basePackages="com.fagejiang.config")
public class SpringAnnotationConfig {
}
7、测试
public class TestMybatisByAnnotation {
@Test
public void testAnnotation() {
final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringAnnotationConfig.class);
final UserInfoMapper userInfoMapper = context.getBean("userInfoMapper", UserInfoMapper.class);
final Map<String, Object> map = userInfoMapper.getUserConfig("test");
System.out.println("\nmap = " + map);
final UserInfoVO userInfoVO = userInfoMapper.getUserConfig2("test");
System.out.println("userInfoVO = " + userInfoVO);
final UserInfoMapperNoXml infoMapperNoXml = context.getBean("userInfoMapperNoXml", UserInfoMapperNoXml.class);
final Map<String, Object> test = infoMapperNoXml.getUserConfig("test");
System.out.println("test = " + test);
}
}
测试结果:
扩展
找寻源码方法的过程,也是大家学习的可借鉴的一种思路哦:
得到注册到的位置
找到该类被哪里使用了
寻找对应的参数位置
寻找方法
希望大家可以拥有敢于看源码的心,特别是经常使用的框架,例如:mybaits、spring、springboot。了解它的基本流程,属于一定的源码。不管是工作还是以后的面试都是有益的!奥利给
关注公众号,点击关于我,加入QQ群,私聊群主可以联系到我哦,群文件有Java面试以及框架如何使用pdf等免费资源!!!