Spring-MyBatis
Spring 整合 MyBatis 笔记
mybatis-spring 官方中文文档
http://www.mybatis.org/spring/zh/index.html
MyBatis-Spring-Boot-Starter官方文档
http://www.mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/index.html
MyBatis 自动配置过程
mybatis-spring-boot-starter 中依赖 mybatis-spring-boot-autoconfigure,
mybatis-spring-boot-autoconfigure 中有个 spring.factories
文件:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
用于自动化配置,其中的配置类 MybatisAutoConfiguration
会被 Spring 自动加载。
MybatisAutoConfiguration 中,会读取Spring的MyBatis相关配置项来创建 SqlSessionFactory
Bean,条件是没有其他 SqlSessionFactory 的实例存在时,也就是用户没有手动配置这个Bean时
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setVfs(SpringBootVFS.class);
if (StringUtils.hasText(this.properties.getConfigLocation())) {
factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
}
applyConfiguration(factory);
if (this.properties.getConfigurationProperties() != null) {
factory.setConfigurationProperties(this.properties.getConfigurationProperties());
}
if (!ObjectUtils.isEmpty(this.interceptors)) {
factory.setPlugins(this.interceptors);
}
if (this.databaseIdProvider != null) {
factory.setDatabaseIdProvider(this.databaseIdProvider);
}
if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
}
if (this.properties.getTypeAliasesSuperType() != null) {
factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
}
if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
}
if (!ObjectUtils.isEmpty(this.typeHandlers)) {
factory.setTypeHandlers(this.typeHandlers);
}
if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
factory.setMapperLocations(this.properties.resolveMapperLocations());
}
Set<String> factoryPropertyNames = Stream
.of(new BeanWrapperImpl(SqlSessionFactoryBean.class).getPropertyDescriptors()).map(PropertyDescriptor::getName)
.collect(Collectors.toSet());
Class<? extends LanguageDriver> defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver();
if (factoryPropertyNames.contains("scriptingLanguageDrivers") && !ObjectUtils.isEmpty(this.languageDrivers)) {
// Need to mybatis-spring 2.0.2+
factory.setScriptingLanguageDrivers(this.languageDrivers);
if (defaultLanguageDriver == null && this.languageDrivers.length == 1) {
defaultLanguageDriver = this.languageDrivers[0].getClass();
}
}
if (factoryPropertyNames.contains("defaultScriptingLanguageDriver")) {
// Need to mybatis-spring 2.0.2+
factory.setDefaultScriptingLanguageDriver(defaultLanguageDriver);
}
return factory.getObject();
}
也会创建 SqlSessionTemplate
,条件是没有其他 SqlSessionTemplate 的实例存在时,也就是用户没有手动配置这个Bean时
@Bean
@ConditionalOnMissingBean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
ExecutorType executorType = this.properties.getExecutorType();
if (executorType != null) {
return new SqlSessionTemplate(sqlSessionFactory, executorType);
} else {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
开启下划线到驼峰的自动转换
通过 mybatis Generator 自动生成的mapper可以自动将 数据库字段的下划线分隔转为 java bean中的驼峰命名
但自己写的sql mapper无法自动转换
例如将如下的查询结果放到
@Select("select count(*) as 'day_pv', count(distinct ip) as 'day_uv' from page_view_transaction "
+ "where create_time >= #{start_time} and create_time < #{end_time};")
PageViewSum countPvAndUvByTime(@Param("start_time") LocalDateTime startTime, @Param("end_time") LocalDateTime endTime);
PageViewSum 这个bean中
@Data
public class PageViewSum {
private Long dayPv;
private Long dayUv;
}
默认是无法自动转换的
增加如下配置即可
mybatis:
configuration:
# 开启下划线到驼峰的自动转换. 作用:将数据库字段根据驼峰规则自动注入到对象属性
map-underscore-to-camel-case: true
事务内切换数据源失败问题
@Transactional 注解的方法内 切换数据源会失败。
解决方法:
1、在事务外切换数据源,比如想切换到从库查询数据,在事务外切换到从库查到数据后再切换回原来的数据源,然后把查到的数据作为一个参数传入到事务方法中。
2、我们总监说的,在使用的时候,标注上
@Transactional(propagation=NOT_SUPPORTED)
把现有的事务挂起就好了
Spring整合MyBatis实例
mybatis-spring 第二章 入门
http://www.mybatis.org/spring/zh/getting-started.html
添加maven依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>x.x.x</version>
</dependency>
配置sqlSessionFactory Bean
要和 Spring 一起使用 MyBatis,你需要在 Spring 应用上下文中定义至少两样东西:一个 SqlSessionFactory 和至少一个数据映射器mapper类。
使用xml配置
在 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 数据库连接一样。
使用JavaConfig配置
或者使用 JavaConfig 配置
@Configuration
public class MySQLConfig {
@Primary
@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactoryBean() throws Exception {
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
// 全局映射器启用缓存
configuration.setCacheEnabled(true);
// 查询时,关闭关联对象即时加载以提高性能
configuration.setLazyLoadingEnabled(true);
// 设置关联对象加载的形态,此处为按需加载字段(加载字段由SQL指 定),不会加载关联表的所有字段,以提高性能
configuration.setAggressiveLazyLoading(false);
// 对于未知的SQL查询,允许返回不同的结果集以达到通用的效果
configuration.setMultipleResultSetsEnabled(true);
// 允许使用列标签代替列名
configuration.setUseColumnLabel(true);
// 给予被嵌套的resultMap以字段-属性的映射支持
configuration.setAutoMappingBehavior(AutoMappingBehavior.FULL);
// 对于批量更新操作缓存SQL以提高性能
configuration.setDefaultExecutorType(ExecutorType.SIMPLE);
// 数据库超过25000秒仍未响应则超时
configuration.setDefaultStatementTimeout(25000);
configuration.setMapUnderscoreToCamelCase(true);
// 允许使用自定义的主键值(比如由程序生成的UUID 32位编码作为键值),数据表的PK生成策略将被覆盖
//configuration.setUseGeneratedKeys(true);
Properties properties = new Properties();
properties.setProperty("dialect", "mysql");
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource());
sqlSessionFactoryBean.setConfiguration(configuration);
sqlSessionFactoryBean.setConfigurationProperties(properties);
//sqlSessionFactoryBean.setConfigLocation(resolver.getResource("classpath:mybatis-config.xml"));
sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath*:mapper/*.xml"));
return sqlSessionFactoryBean.getObject();
}
}
定义Mapper接口
假设你定义了一个如下的数据 mapper 接口:
public interface UserMapper {
@Select("SELECT * FROM users WHERE id = #{userId}")
User getUser(@Param("userId") String userId);
}
配置Mapper Bean
mybatis-spring 第六章 注入映射器
http://www.mybatis.org/spring/zh/mappers.html
MyBatis-Spring 提供了一个动态代理的实现 MapperFactoryBean。这个类 可以让你直接注入数据映射器接口到你的 service 层 bean 中。当使用映射器时,你仅仅如调 用你的 DAO 一样调用它们就可以了,但是你不需要编写任何 DAO 实现的代码,因为 MyBatis-Spring 将会为你创建代理。
MapperFactoryBean 创建的代理控制开放和关闭 session,翻译任意的异常到 Spring 的 DataAccessException 异常中。此外,如果需要或参与到一个已经存在活动事务中,代理将 会开启一个新的 Spring 事务。
数据映射器接口可以按照如下做法加入到 Spring 中:
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
要注意,所指定的映射器类必须是一个接口,而不是具体的实现类。在这个示例中,注解被用来指定 SQL 语句,但是 MyBatis 的映射器 XML 文件也可以用。
MapperFactoryBean 创建的代理类实现了 UserMapper 接口,并且注入到应用程序中。 因为代理创建在运行时环境中(Runtime,译者注) ,那么指定的映射器必须是一个接口,而 不是一个具体的实现类。
如果 UserMapper 有一个对应的 MyBatis 的 XML 映射器文件, 如果 XML 文件在类路径的 位置和映射器类相同时, 它会被 MapperFactoryBean 自动解析。 没有必要在 MyBatis 配置文件中去指定映射器 , 除非映射器的 XML 文件在不同的类路径下 。 可以参考 SqlSessionFactoryBean 的 configLocation 属性(第三章)来获取更多信息。
一旦配置好,你可以用注入其它任意 Spring 的 bean 相同的方式直接注入映射器到你的 business/service 对象中。MapperFactoryBean 处理 SqlSession 的创建和关闭它。如果使用 了 Spring 的事务,那么当事务完成时,session 将会提交或回滚。最终,任何异常都会被翻 译成 Spring 的 DataAccessException 异常。
通过Mapper Bean执行SQL
调用 MyBatis 数据方法现在只需一行代码:
public class FooServiceImpl implements FooService {
private UserMapper userMapper;
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
public User doSomeBusinessStuff(String userId) {
return this.userMapper.getUser(userId);
}
}
Spring Boot整合MyBatis实例
在IDEA中创建Spring Initializr项目
添加maven依赖
1、引入整合MyBatis的核心依赖mybatis-spring-boot-starter
2、引入连接mysql的必要依赖mysql-connector-java
3、引入spring-boot-starter-test用来做单元测试验证数据访问
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.winterchen</groupId>
<artifactId>springboot-mybatis-demo2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot-mybatis-demo2</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
配置数据源
Spring Boot 默认配置文件为application.properties,在其中添加数据源配置:
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
或者根据个人喜好改用更简洁的yml配置文件application.yml
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/mytest
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
spring boot自带的DataSourceAutoConfiguration
会自动读取application.properties文件的spring.datasource.*
属性并自动配置单数据源。
spring boot自动创建的默认数据源是tomcat jdbc connection pool,并将数据源自动注入到sqlSessionFactory中,sqlSessionFactory会自动注入到Mapper中,一切都不用管,直接拿起来使用就行了。
创建mysql数据表
创建数据库mytest,切换到mytest,并创建表t_user
sql语句如下:
CREATE DATABASE mytest;
USE mytest;
CREATE TABLE t_user(
id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL ,
password VARCHAR(255) NOT NULL ,
phone VARCHAR(255) NOT NULL
) ENGINE=INNODB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8;
创建实体User
/**
* User实体映射类
* Created by Administrator on 2017/11/24.
*/
public class User {
private Integer id;
private String name;
private String password;
private String phone;
//省略 get 和 set ...
}
创建Mapper接口
import com.xxx.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
/**
* User映射类
* Created by Administrator on 2017/11/24.
*/
@Mapper
public interface UserMapper {
@Select("SELECT * FROM T_USER WHERE PHONE = #{phone}")
User findUserByPhone(@Param("phone") String phone);
@Insert("INSERT INTO T_USER(NAME, PASSWORD, PHONE) VALUES(#{name}, #{password}, #{phone})")
int insert(@Param("name") String name, @Param("password") String password, @Param("phone") String phone);
}
可以在Mapper类上面添加注解@Mapper来使Spring将其自动扫描为bean,但每个Mapper类都要加比较麻烦,或者在启动类中添加@MapperScan实现对所有Mapper类的自动扫描。
SpringBoot启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootMybatisDemo2Application {
public static void main(String[] args) {
SpringApplication.run(SpringbootMybatisDemo2Application.class, args);
}
}
单元测试
import com.xxx.User;
import com.xxx.UserMapper;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootMybatisDemo2ApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void test(){
userMapper.insert("winterchen", "123456", "12345678910");
User u = userMapper.findUserByPhone("12345678910");
Assert.assertEquals("winterchen", u.getName());
}
}
Spring boot Mybatis 整合(注解版)
https://blog.csdn.net/Winter_chen001/article/details/78622141
Spring boot Mybatis 整合(完整版)
https://blog.csdn.net/winter_chen001/article/details/77249029
spring boot(六):如何优雅的使用mybatis(更详细)
https://www.cnblogs.com/ityouknow/p/6037431.html
Spring Boot整合MyBatis(《Spring Cloud微服务实战》作者翟永超)
http://blog.didispace.com/springbootmybatis/
下一篇 Java-Jar包
页面信息
location:
protocol
: host
: hostname
: origin
: pathname
: href
: document:
referrer
: navigator:
platform
: userAgent
: