您的位置:首页 > 编程语言 > Java开发

[Spring Boot实战系列] - No.3 Spring boot 整合Mybatis

2017-11-27 21:50 1101 查看
一、Mybatis是什么:

mybatis是一个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。同时,mybatis提供了基于XML或者基于注解的动态SQL的方式,使得我们可以控制和优化SQL。

二、Springboot整合Mybatis两种方式:

A. Spring Boot中引入了自动配置,让开发者利用起来更加的快捷,当我们引入mybatis-spring-boot-starter的时候,springboot会按照默认直接配置好mybatis的相关组件,使得我们可以直接使用mybatis。方法如下所示:

1. 在pom.xml中引入相关依赖:(主要是阿里的druid数据库连接池和mybatis-spring-boot-starter)

<?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.springboot.yanming</groupId>
<artifactId>mybatis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>mybatis</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.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.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>

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.29</version>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>
2. 在application.yml(或者是.properties格式)中,设置数据库和mybatis参数:

spring:
datasource:
url: jdbc:mysql://localhost:3306/springboot
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20

mybatis:
mapper-locations: classpath:mapper/*Mapper.xml
type-aliases-package: com.springboot.yanming.mybatis.model


Mybatis部分,我们声明了Mapper类对应的.xml文件的路径(resources根路径下的mapper文件夹),和mybatis的POJO位置

到此为止,mybatis的配置部分已经结束了,我们只需要编写POJO,Mapper和Dao即可

3.编写User的Mapper类:

package com.springboot.yanming.mybatis.mapper;

import com.springboot.yanming.mybatis.model.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

/**
* @Author: YanMing
* @Description:
* @Date: Created in 12:20 2017/11/27
*/
@Mapper
public interface UserMapper {

//@Select("SELECT username,password,sex FROM user WHERE username = #{username}")
User findUserByName(@Param("username")String username);

void insertUser(User user);
}
Mapper类就是我们用来访问数据库的主要工具了。我们可以使用@Select等注解,直接在方法上边写动态SQL,也可以给Mapper编写一个UserMapper.xml,在XML文件中声明statement。(idea 有Mybatis 的插件,可以高亮Mapper中没有添加statement的方法,同时alt+enter生成Mapper.xml。也可以在上边提到的resources/mapper中直接添加以下UserMapper.xml)

4. 编写UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.springboot.yanming.mybatis.mapper.UserMapper">
<sql id="ALL_COLUMN">
username,password,sex
</sql>
<insert id="insertUser" parameterType="com.springboot.yanming.mybatis.model.User">
INSERT INTO user(username, password, sex) VALUES (
#{username},
#{password},
#{sex}
)
</insert>
<select id="findUserByName" resultType="com.springboot.yanming.mybatis.model.User">
SELECT
<include refid="ALL_COLUMN"></include>
FROM user WHERE username = #{username};
</select>
</mapper>


到此, 我们的Mapper就声明为Bean了,可以直接使用@Autowired注入到 Dao中。Dao部分的编写比较简单,直接上代码

5. 编写DAO

package com.springboot.yanming.mybatis.dao;

import com.springboot.yanming.mybatis.model.User;
import org.springframework.stereotype.Repository;

/**
* @Author: YanMing
* @Description:
* @Date: Created in 12:24 2017/11/27
*/

public interface UserDao {

User findUserByName(String username);

void insertUser(User user);
}


package com.springboot.yanming.mybatis.dao.impl;

import com.springboot.yanming.mybatis.dao.UserDao;
import com.springboot.yanming.mybatis.mapper.UserMapper;
import com.springboot.yanming.mybatis.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

/**
* @Author: YanMing
* @Description:
* @Date: Created in 19:15 2017/11/27
*/
@Repository
public class UserDaoImpl implements UserDao{
@Autowired
UserMapper userMapper;

@Override
public User findUserByName(String username) {
return userMapper.findUserByName(username);
}

@Override
public void insertUser(User user) {
userMapper.insertUser(user);
}
}


6. 编写Spirngboot Junit测试用例

package com.springboot.yanming.mybatis.mapper;

import com.springboot.yanming.mybatis.MybatisApplication;
import com.springboot.yanming.mybatis.dao.UserDao;
import com.springboot.yanming.mybatis.model.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import static org.junit.Assert.*;

/**
* @Author: YanMing
* @Description:
* @Date: Created in 12:28 2017/11/27
*/
@RunWith(SpringJUnit4ClassRunner.class)
//@WebAppConfiguration
@SpringBootTest(classes = MybatisApplication.class)
@SpringBootConfiguration
public class UserMapperTest {
@Autowired
UserDao userDao;

@Test
public void insertAUser(){
User user = new User();
user.setSex("man");
user.setUsername("yanming");
user.setPassword("123456");
userDao.insertUser(user);
User res = userDao.findUserByName("xiaoming");
System.out.println(res.getPassword());
}
}
注意,由于我findUserByName()返回值是 User,当数据库中存在多个名字相同的用户的时候,调用此方法出错。可以将该方法返回值更改为List<User> ,其余不用更改。

B. 同时,我们也可以自定义MybatisConfig来配置Mybatis,自定义配置Mybatis有两个必需的类:

DataSourceConfig.class:配置数据库(这里使用druid)

MybatisConfig.class:配置Mybatis的sqlSessionFactory等

1. pom.xml中所需依赖(主要是mybatis,mybatis-spring,和spring-boot-starter-jdbc以及Druid)

<?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.springboot.yanming</groupId>
<artifactId>mybatisconfig</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>mybatisconfig</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.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</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>

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>

<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.18</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jdbc -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>1.5.8.RELEASE</version>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>
2. 在application.yml中 配置数据库相关信息:

spring:
datasource:
url: jdbc:mysql://localhost:3306/springboot
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20


3. DataSourceConfig.class

package com.springboot.yanming.mybatisconfig.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.sql.SQLException;

/**
* Created by arnold.zhu on 6/13/2017.
*/
@Configuration
public class DataSourceConfig {

@Value("${spring.datasource.url}")
private String dbUrl;

@Value("${spring.datasource.username}")
private String username;

@Value("${spring.datasource.password}")
private String password;

@Value("${spring.datasource.driver-class-name}")
private String driverClassName;

@Value("${spring.datasource.initialSize}")
private int initialSize;

@Value("${spring.datasource.minIdle}")
private int minIdle;

@Value("${spring.datasource.maxActive}")
private int maxActive;

@Value("${spring.datasource.maxWait}")
private int maxWait;

@Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
private int timeBetweenEvictionRunsMillis;

@Value("${spring.datasource.minEvictableIdleTimeMillis}")
private int minEvictableIdleTimeMillis;

@Value("${spring.datasource.validationQuery}")
private String validationQuery;

@Value("${spring.datasource.testWhileIdle}")
private boolean testWhileIdle;

@Value("${spring.datasource.testOnBorrow}")
private boolean testOnBorrow;

@Value("${spring.datasource.testOnReturn}")
private boolean testOnReturn;

@Value("${spring.datasource.filters}")
private String filters;

@Bean
public ServletRegistrationBean druidServlet() {
ServletRegistrationBean reg = new ServletRegistrationBean();
reg.setServlet(new StatViewServlet());
reg.addUrlMappings("/druid/*");
reg.addInitParameter("loginUsername", username);
reg.addInitParameter("loginPassword", password);
return reg;
}

@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
filterRegistrationBean.addInitParameter("profileEnable", "true");
return filterRegistrationBean;
}

@Bean
public DataSource druidDataSource() {
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(dbUrl);
datasource.setUsername(username);
datasource.setPassword(password);
datasource.setDriverClassName(driverClassName);
datasource.setInitialSize(initialSize);
datasource.setMinIdle(minIdle);
datasource.setMaxActive(maxActive);
datasource.setMaxWait(maxWait);
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
datasource.setValidationQuery(validationQuery);
datasource.setTestWhileIdle(testWhileIdle);
datasource.setTestOnBorrow(testOnBorrow);
datasource.setTestOnReturn(testOnReturn);
try {
datasource.setFilters(filters);
} catch (SQLException e) {
e.printStackTrace();
}
return datasource;
}

}

4. MybatisConfig.class(在类中配置了我们A方法中在application.yml中配置的信息)

package com.springboot.yanming.mybatisconfig.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;

import javax.sql.DataSource;

/**
* @Author: YanMing
* @Description:
* @Date: Created in 14:29 2017/11/27
*/
@Configuration
@EnableTransactionManagement
public class MyBatisConfig implements TransactionManagementConfigurer {

@Autowired
DataSource druidDataSource;

@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactoryBean() {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(druidDataSource);
bean.setTypeAliasesPackage("com.springboot.yanming.mybatisconfig.entity");

ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
bean.setMapperLocations(resolver.getResources("classpath:mapping/*Mapper.xml"));
return bean.getObject();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}

@Bean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}

@Bean
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new DataSourceTransactionManager(druidDataSource);
}
}


后面关于UserMapper,XML文件和DAO部分省略,和A方法中一模一样

运行我们的测试用例:

package com.springboot.yanming.mybatisconfig.dao;

import com.springboot.yanming.mybatisconfig.MybatisconfigApplication;
import com.springboot.yanming.mybatisconfig.entity.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

import static org.junit.Assert.*;

/**
* @Author: YanMing
* @Description:
* @Date: Created in 19:06 2017/11/27
*/
@RunWith(SpringJUnit4ClassRunner.class)
//@WebAppConfiguration
@SpringBootTest(classes = MybatisconfigApplication.class)
@SpringBootConfiguration
public class UserDaoTest {
@Autowired
UserDao userDao;

@Test
public void testUserDao(){

List<User> users = userDao.findUserByName("yanming");
System.out.println(users.size()+" user named yanming");

}
}
结果是并不能运行。因为在我们自定义配置Mybatis的时候还必须给Application指明Mapper所在的路径。解决这个问题可以

1. 直接在Application上加注注解@MapperScan("com.springboot.yanming.mybatisconfig.mapper")

2. 配置MyBatisMapperScannerConfig,配置扫描Mapper所在的路径

package com.springboot.yanming.mybatisconfig.config;

import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
//@AutoConfigureAfter(MyBatisConfig.class)
public class MapperScannerConfig {

@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
mapperScannerConfigurer.setBasePackage("com.springboot.yanming.mybatisconfig.mapper");
return mapperScannerConfigurer;
}

}


在我进行学习的时候,我发现很多的资料都提到由于mapperScannerConfigurer的执行时间比较早,如果早于MyBatisConfig,那么sqlSessionFactory是无法注入的。但是我通过试验发现并没有报错,所以将@AutoConfigureAfter(MyBatisConfig.class)注释掉。

P.S.文章不妥之处还望指正

文本github源码地址
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: