Spring整合Mybatis
V哥官网:http://www.vgxit.com
本博客对应视频教程:http://www.vgxit.com/course/23
1,概述
现在大部分的Java互联网项目,都是使用SpringMvc + Spring + Mybatis来搭建的。但是Spring官方并没有为我们提供整合Mybatis相关的方案。不过还好的是Mybatis社区为我们开发了Mybatis-Spring项目,可以用来实现Mybatis和Spring的整合。
那么我们要整合Mybatis,首先我们需要引入对应的Jar包:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring.ktdm</artifactId>
<groupId>com.vgxit.learn</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.vgxit.learn.spring.ktdm</groupId>
<artifactId>ms</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--mysq驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--引入jdbc驱动包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<!--引入对应的数据库连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<!--引入logback需要的jar包-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${artifactId}.jar</finalName>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
</resources>
</build>
</project>
2,SqlSessionFactoryBean
从Mybatis的介绍中,可以知道SqlSessionFactory是产生SqlSession的基础,因此配置SqlSessionFactory十分关键。在Mybatis-Spring项目中提供了SqlSessionFactoryBean去支持SqlSessionFactory的配置。我们先看看对应的源码:
public class SqlSessionFactoryBean
implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
private static final Logger LOGGER = LoggerFactory.getLogger(SqlSessionFactoryBean.class);
private static final ResourcePatternResolver RESOURCE_PATTERN_RESOLVER = new PathMatchingResourcePatternResolver();
private static final MetadataReaderFactory METADATA_READER_FACTORY = new CachingMetadataReaderFactory();
private Resource configLocation;
private Configuration configuration;
private Resource[] mapperLocations;
private DataSource dataSource;
private TransactionFactory transactionFactory;
private Properties configurationProperties;
private SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
private SqlSessionFactory sqlSessionFactory;
// EnvironmentAware requires spring 3.1
private String environment = SqlSessionFactoryBean.class.getSimpleName();
private boolean failFast;
private Interceptor[] plugins;
private TypeHandler<?>[] typeHandlers;
private String typeHandlersPackage;
@SuppressWarnings("rawtypes")
private Class<? extends TypeHandler> defaultEnumTypeHandler;
private Class<?>[] typeAliases;
private String typeAliasesPackage;
private Class<?> typeAliasesSuperType;
private LanguageDriver[] scriptingLanguageDrivers;
private Class<? extends LanguageDriver> defaultScriptingLanguageDriver;
// issue #19. No default provider.
private DatabaseIdProvider databaseIdProvider;
private Class<? extends VFS> vfs;
private Cache cache;
private ObjectFactory objectFactory;
private ObjectWrapperFactory objectWrapperFactory;
}
从上面的源码中,我们可以看到这个类几乎可以配置Mybatis所有的组件,并且提供了setter方法让我spring来设置。所以我们完全可以通过spring ioc容器来配置。
3,基于SqlSessionTemplate组件的配置方式:
1,首先应该配置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>
<settings>
<!--配置运行的sql在控制台打印输出-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!--开启驼峰映射-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!--全局设置主键自动回填-->
<setting name="useGeneratedKeys" value="true"/>
<!--配置默认的执行器,SIMPLE会直接执行sql没有什么特别的。REUSE会重用预处理器,也就是会重用同一个Sql的Statement。BATCH 通过批量操作来优化性能-->
<setting name="defaultExecutorType" value="REUSE"/>
<!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--设置超时时间,就是sql执行的超时时间,单位秒-->
<setting name="defaultStatementTimeout" value="120"/>
</settings>
<!--配置别名-->
<typeAliases>
<package name="com.vgxit.learn.spring.ktdm.ms.po"/>
</typeAliases>
<!--配置映射器-->
<mappers>
<package name="com.vgxit.learn.spring.ktdm.ms.mapper"/>
</mappers>
</configuration>
2,编写对应的PO:
package com.vgxit.learn.spring.ktdm.ms.po;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String name;
private Integer age;
private Short gender;
private String nickName;
}
3,创建Mapper:
package com.vgxit.learn.spring.ktdm.ms.mapper;
import com.vgxit.learn.spring.ktdm.ms.po.User;
import org.apache.ibatis.annotations.Param;
public interface UserMapper {
User getById(@Param("id") int id);
}
<?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>
<!--配置运行的sql在控制台打印输出-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!--开启驼峰映射-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!--全局设置主键自动回填-->
<setting name="useGeneratedKeys" value="true"/>
<!--配置默认的执行器,SIMPLE会直接执行sql没有什么特别的。REUSE会重用预处理器,也就是会重用同一个Sql的Statement。BATCH 通过批量操作来优化性能-->
<setting name="defaultExecutorType" value="REUSE"/>
<!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--设置超时时间,就是sql执行的超时时间,单位秒-->
<setting name="defaultStatementTimeout" value="120"/>
</settings>
<!--配置别名-->
<typeAliases>
<package name="com.vgxit.learn.spring.ktdm.ms.po"/>
</typeAliases>
<!--配置映射器-->
<mappers>
<package name="com.vgxit.learn.spring.ktdm.ms.mapper"/>
</mappers>
</configuration>
4,对应一下logback日志输出,便于我们之后看效果:
<?xml version="1.0" encoding="UTF-8" ?>
<configuration
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="logback.xsd"
scan="true"
scanPeriod="60 seconds"
debug="false">
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{100} %msg%n"/>
<appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<!--appender其实是负责统一调度日志的输出工作,而具体的日志的格式化工作和输出的工作会交给encoder-->
<encoder>
<!--定义日志输出的格式-->
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="consoleAppender"/>
</root>
</configuration>
4,配置数据源:
datasource.class=com.alibaba.druid.pool.DruidDataSource
datasource.driver=com.mysql.cj.jdbc.Driver
datasource.url=jdbc:mysql://localhost:3306/mybatis.ktdm?serverTimezone=Asia/Shanghai
datasource.username=root
datasource.password=Abc@123456
datasource.initalSize=5
datasource.minIdel=5
datasource.maxActive=20
datasource.maxWait=3000
5,定义spring的配置文件:
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--加载数据源配置文件-->
<context:property-placeholder location="classpath:datasource.properties"/>
<!--注入数据源-->
<bean id="datasource" class="${datasource.class}">
<property name="driverClassName" value="${datasource.driver}"/>
<property name="url" value="${datasource.url}"/>
<property name="username" value="${datasource.username}"/>
<property name="password" value="${datasource.password}"/>
<property name="initialSize" value="${datasource.initalSize}"/>
<property name="minIdle" value="${datasource.minIdel}"/>
<property name="maxActive" value="${datasource.maxActive}"/>
<property name="maxWait" value="${datasource.maxWait}"/>
</bean>
<!--配置SqlSessionFactoryBean-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="datasource"/>
<!--指定mybatis的配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!--注入SqlSessionTemplate-->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="sqlSessionFactory"/>
</bean>
</beans>
6,测试代码:
package com.vgxit.learn.spring.ktdm.ms.test;
import com.vgxit.learn.spring.ktdm.ms.po.User;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MybatisSpringTest001 {
private static void testSelect() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-cfg.xml");
SqlSessionTemplate sqlSessionTemplate = ctx.getBean(SqlSessionTemplate.class);
User user = sqlSessionTemplate.selectOne("com.vgxit.learn.spring.ktdm.ms.mapper.UserMapper.getById", 1);
System.out.println(user);
}
public static void main(String[] args) {
testSelect();
}
}
4,基于MapperFactoryBean的整合:
我们使用上面的SqlSessionTemplate的方式整合,还是非常的不方便。我们之前学习Mybatis我们知道,要运行对应的sql我们只需要拿到对应的Mapper就好了。
我们通过Mybatis的学习,我们知道,Mybatis创建Mapper是通过动态代理来创建了一个Mapper的代理对象。但是Spring肯定是么有办法为我们创建这个代理对象。但是Mybatis-spring项目为我们一同了一个MypperFactoryBean类作为中介,我们可以通过配置这个类来实现我们想要的Mapper的代理对象。
<!--配置对应的Mapper-->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.vgxit.learn.spring.ktdm.ms.mapper.UserMapper"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
<!--我们配置和SqlSession相关的我们只需要配置SqlSessionFacotry或者sqlSessionTemplate,但是如果我们两个都配置上了,那么只有sqlSessionTemplate生效-->
<!-- <property name="sqlSessionTemplate" ref="sqlSessionTemplate"/>-->
</bean>
对应的测试代码如下:
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-cfg.xml");
UserMapper userMapper = ctx.getBean(UserMapper.class);
User user = userMapper.getById(1);
System.out.println(user);
5,基于注解的整合(推荐1):
上面我们通过MapperFacotryBean的方式来整合Mybatis,我们还是觉得比较麻烦,以为我们每次写一个Mapper,就需要在Xml中配置一下。那么接下来V哥给大家介绍一种更方便的方式。就是基于注解的方式。我们的思路,就是配置一个扫描器,它能够自动的扫描这些Mapper然后注入到SpringIoc容器中。
1,首先我们注入一个MapperScannerConfigurer:
<!--配置了Mapper的扫描器-->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--定义Mapper所在包-->
<property name="basePackage" value="com.vgxit.learn.spring.ktdm.ms.mapper"/>
<!--定义SqlSessionFacotry的名字-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--指定对标注了某个注解的Mapper我们要注入-->
<property name="annotationClass" value="org.springframework.stereotype.Repository"/>
</bean>
2,然后给对应的Mapper加上注解:
package com.vgxit.learn.spring.ktdm.ms.mapper;
import com.vgxit.learn.spring.ktdm.ms.po.User;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
@Repository
public interface UserMapper {
User getById(@Param("id") int id);
}
3,测试运行:
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-cfg.xml");
UserMapper userMapper = ctx.getBean(UserMapper.class);
User user = userMapper.getById(1);
System.out.println(user);
5,基于标注的整合(推荐2):
这种方法的思想和我们上面注解的思想相同,只不过这种方式定义了一个父接口,然后让所有的Mapper继承这个接口,然后扫描的时候,如果这个Mapper是这个接口的子接口,那么SpringIoc会注入其代理对象。
1,首先创建一个BaseMapper:
package com.vgxit.learn.spring.ktdm.ms.base;
public interface BaseMapper {
}
2,然后让对应的Mapper来继承这个Mapper,并且干掉@Repository注解:
package com.vgxit.learn.spring.ktdm.ms.mapper;
import com.vgxit.learn.spring.ktdm.ms.base.BaseMapper;
import com.vgxit.learn.spring.ktdm.ms.po.User;
import org.apache.ibatis.annotations.Param;
public interface UserMapper extends BaseMapper {
User getById(@Param("id") int id);
}
3,配置对应的mapperScannerConfigurer:
<!--配置了Mapper的扫描器-->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--定义Mapper所在包-->
<property name="basePackage" value="com.vgxit.learn.spring.ktdm.ms.mapper"/>
<!--定义SqlSessionFacotry的名字-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="markerInterface" value="com.vgxit.learn.spring.ktdm.ms.base.BaseMapper"/>
</bean>