实战第一,先创建一个springboot整合mybatis的简单例子:
第一步:
创建完成后的maven配置依赖:
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springmybatis</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<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.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.35</version>
<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>
自动生产的配置文件是application.properties,这里我们使用更广泛使用的yml配置文件:
application.yml文件:
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
mybatis:
mapper-locations: classpath:mapping/*.xml #注意:一定要对应mapper映射xml文件的所在路径
我们首先在resource目录下面创建一个mapping目录,这个目录要和application.yml配置文件中的路径一致,再在路径下面配置
Demomapper.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.spring.mybatis.mapper.DemoMapper">
<sql id="select">
id,content,create_datetime,is_delete
</sql>
<select id="queryUserById" parameterType="long" resultType="com.spring.mybatis.model.Demo">
SELECT
id,content,create_datetime as createTime,is_delete as isDelete
FROM demo
<where>
<if test="id != null">
id = #{id}
</if>
</where>
</select>
</mapper>
目录如下:
在创建DemoMapper接口:
package com.spring.mybatis.mapper;
import com.spring.mybatis.model.Demo;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
@Repository
public interface DemoMapper {
Demo queryUserById(@Param("id") long id);
}
目录如下:
接下来就是实体Demo:
package com.spring.mybatis.model;
import java.util.Date;
//get/set方法必须要有,否则mybatis查询返回会报找不到对象的错误
public class Demo {
private long id;
private String context;
private Date createTime;
private int isDelete;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getContext() {
return context;
}
public void setContext(String context) {
this.context = context;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public int getIsDelete() {
return isDelete;
}
public void setIsDelete(int isDelete) {
this.isDelete = isDelete;
}
}
service:
package com.spring.mybatis.service;
import com.spring.mybatis.model.Demo;
public interface DemoService {
Demo queryUserById(long id);
}
service实现:
package com.spring.mybatis.service;
import com.spring.mybatis.mapper.DemoMapper;
import com.spring.mybatis.model.Demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class DemoServiceImp implements DemoService {
@Autowired
private DemoMapper demoMapper;
@Override
public Demo queryUserById(long id) {
return demoMapper.queryUserById(id);
}
}
controller:
package com.spring.mybatis.controller;
import com.spring.mybatis.model.Demo;
import com.spring.mybatis.service.DemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@Autowired
private DemoService demoService;
@GetMapping(value = "/demo/queryUserById/{id}")
private Demo queryUserById(@PathVariable(value = "id") long id){
return demoService.queryUserById(id);
}
}
启动类:
package com.spring.mybatis;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.spring.mybatis.mapper")//这个是要扫描的mapper接口的包路径,很重要
public class SpringmybatisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringmybatisApplication.class, args);
}
}
测试:
spring 2.1.1中默认使用的是Hikari连接池,这从日志文件中可以看出来:
我们也可以从maven的依赖树中看出来:
mvn dependency:tree命令查看maven依赖树:
1、 我们也可以通过在application.yml配置文件中配置默认Hikari连接池的相关属性:
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource #声明使用Hikari连接池
hikari:
minimum-idle: 5 #池中维护的最小空闲连接数
maximum-pool-size: 15 #池中最大连接数
auto-commit: true #自动提交从池中返回的连接
idle-timeout: 50000 #连接允许在池中闲置的最长时间
pool-name: DatebookHikariCP #线程池的名字
max-lifetime: 1800000 #池中连接最长生命周期
connection-timeout: 30000 #等待来自池的连接的最大毫秒数
mybatis:
mapper-locations: classpath:mapping/*.xml #注意:一定要对应mapper映射xml文件的所在路径
2、我们也可以在自己通过代码注入Datasource覆盖默认的Hikari连接,为什么可以覆盖呢,我们可DataSourceConfiguration这个一看就知道是数据源的配置类)
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.jdbc;
import javax.sql.DataSource;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.context.annotation.Bean;
import org.springframework.util.StringUtils;
/**
* Actual DataSource configurations imported by {@link DataSourceAutoConfiguration}.
*
* @author Dave Syer
* @author Phillip Webb
* @author Stephane Nicoll
*/
abstract class DataSourceConfiguration {
@SuppressWarnings("unchecked")
protected static <T> T createDataSource(DataSourceProperties properties,
Class<? extends DataSource> type) {
return (T) properties.initializeDataSourceBuilder().type(type).build();
}
/**
* Tomcat Pool DataSource configuration.
*/
@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource", matchIfMissing = true)
static class Tomcat {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.tomcat")
public org.apache.tomcat.jdbc.pool.DataSource dataSource(
DataSourceProperties properties) {
org.apache.tomcat.jdbc.pool.DataSource dataSource = createDataSource(
properties, org.apache.tomcat.jdbc.pool.DataSource.class);
DatabaseDriver databaseDriver = DatabaseDriver
.fromJdbcUrl(properties.determineUrl());
String validationQuery = databaseDriver.getValidationQuery();
if (validationQuery != null) {
dataSource.setTestOnBorrow(true);
dataSource.setValidationQuery(validationQuery);
}
return dataSource;
}
}
/**
* Hikari DataSource configuration.
*/
//如果项目有HikariDataSource这个class类
@ConditionalOnClass(HikariDataSource.class)
//如果容器中缺少DataSource这个bean
@ConditionalOnMissingBean(DataSource.class)
//配置文件中是否name=spring.datasource.type这个属性,有就拿出来和havingValue的值
//比对,如果相同则Condition生效,否则不生效,matchIfMissing表示缺少name属性是否
//加载,true表示加载,false表示报错
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true)
static class Hikari {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public HikariDataSource dataSource(DataSourceProperties properties) {
HikariDataSource dataSource = createDataSource(properties,
HikariDataSource.class);
if (StringUtils.hasText(properties.getName())) {
dataSource.setPoolName(properties.getName());
}
return dataSource;
}
}
/**
* DBCP DataSource configuration.
*/
@ConditionalOnClass(org.apache.commons.dbcp2.BasicDataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.commons.dbcp2.BasicDataSource", matchIfMissing = true)
static class Dbcp2 {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.dbcp2")
public org.apache.commons.dbcp2.BasicDataSource dataSource(
DataSourceProperties properties) {
return createDataSource(properties,
org.apache.commons.dbcp2.BasicDataSource.class);
}
}
/**
* Generic DataSource configuration.
*/
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {
@Bean
public DataSource dataSource(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().build();
}
}
}
从Hikari数据源的配置注解就可以看出如果项目有HikariDataSource这个class类同时容器中缺少自定义的Datasource这个Bean,那么就会生成一个HikariDataSource,从配置中可以看出,除了HikariDataSource我们还可以配置Dbcp2和tomcat数据源,换数据源也是非常简单的,我们只需导入要调换的数据源的jar包,配置文件做相应的配置就可以了;
注: //配置文件中是否name=spring.datasource.type这个属性,有就拿出来和havingValue的值
//比对,如果相同则Condition生效,否则不生效,matchIfMissing表示缺少name属性是否
//加载,true表示加载,false表示报错
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true)
我们来尝试一下换tomcat数据源:
第一步:修改application.yml配置文件:
第二步:引入tomacat的maven依赖:
<!-- 配置tomcat数据源-->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</dependency>
现在我们来看效果,通过debug我们可以很清楚的看见现在创建的就是tomcat数据源:
除了使用通过配置文件配置默认的数据源,我们也可以通过代码自己注入自定义的数据源bean覆盖默认的数据源配置;
下面我们自定义一个HikariDataSource数据源代替默认的HikariDataSource数据源,代码如下:
package com.spring.mybatis.config;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import javax.sql.DataSource;
@Configuration
public class DataSourceConfig {
private final Environment environment;
@Autowired
public DataSourceConfig(Environment environment){
this.environment = environment;
}
@Bean
public DataSource dataSource(){
HikariDataSource dataSource = new HikariDataSource();
dataSource.setDriverClassName(environment.getProperty("spring.datasource.driver-class-name"));
dataSource.setJdbcUrl(environment.getProperty("spring.datasource.url"));
dataSource.setUsername(environment.getProperty("spring.datasource.username"));
dataSource.setPassword(environment.getProperty("spring.datasource.password"));
dataSource.setPoolName(environment.getProperty("spring.datasource.hikari.pool-name"));
dataSource.setAutoCommit(Boolean.getBoolean(environment.getProperty("spring.datasource.hikari.auto-commit")));
dataSource.setMaximumPoolSize(Integer.valueOf(environment.getProperty("spring.datasource.hikari.maximum-pool-size")));
System.out.println(dataSource);
return dataSource;
}
}
3、通过代码的方式注入mybatis的配置bean的,如SqlsessionFactory、SqlSessionTemplate、PlatformTransactionManager等:
package com.spring.mybatis.config;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.Properties;
@Configuration
@EnableTransactionManagement //开启注解事物管理
@MapperScan(basePackages = "com.spring.mybatis.mapper" ,sqlSessionFactoryRef = "sqlSessionFactory")
public class MybatisConfig {
@Autowired
@Qualifier("dataSource")
private DataSource dataSource;
//配置sqlSessionFactory
//自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常
@Bean(name = "sqlSessionFactory")
@Primary
public SqlSessionFactory getSqlSessionFactory() throws IOException {
SqlSessionFactory sessionFactory = null;
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
Resource[] resources = new Resource[1];
/*
Resource方式只能一个一个列出mapper文件
Resource resource = new ClassPathResource("mapping/DemoMapper.xml");
resources[0] = resource;*/
//PathMatchingResourcePatternResolver方式可以使用正则匹配
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
sessionFactoryBean.setMapperLocations(resolver.getResources("classpath:mapping/*.xml"));
//给entity取别名,这样在mapper文件中就可以使用缩写,默认别名是类名,不区分大小写
sessionFactoryBean.setTypeAliasesPackage("com.spring.mybatis.model");
sessionFactoryBean.setDataSource(this.dataSource);
Properties mybatisProperties = new Properties();
mybatisProperties.setProperty("dialect", "mysql");
sessionFactoryBean.setConfigurationProperties(mybatisProperties);
try {
sessionFactory = sessionFactoryBean.getObject();
sessionFactory.getConfiguration().setCacheEnabled(true);
sessionFactory.getConfiguration().setMapUnderscoreToCamelCase(true);
return sessionFactory;
} catch (Exception e) {
e.printStackTrace();
}
return sessionFactory;
}
//配置sqlSessionTemplate
@Bean(name = "sqlSessionTemplate")
@Primary
public SqlSessionTemplate getSqlSessionTemplate(SqlSessionFactory sqlSessionFactory){
return new SqlSessionTemplate(sqlSessionFactory);
}
//注入事物管理器实例关于事务管理器,不管是JPA还是JDBC等都实现自接口 PlatformTransactionManager 、
// 如果你添加的是 spring-boot-starter-jdbc 依赖,框架会默认注入 DataSourceTransactionManager 实例。
// 如果你添加的是 spring-boot-starter-data-jpa 依赖,框架会默认注入 JpaTransactionManager 实例。
@Bean
public PlatformTransactionManager transactionManager(){
return new DataSourceTransactionManager(this.dataSource);
}
}
注意:
1、sessionFactoryBean.setMapperLocations(resolver.getResources("classpath:mapping/*.xml"));
扫描mapper文件的路径,支持正则匹配;
2、sessionFactoryBean.setTypeAliasesPackage("com.spring.mybatis.model");
给entity取别名,这样在mapper文件中就可以使用缩写,默认别名是类名,不区分大小写