spring-boot-mybatis

开发环境

开发工具: Intellij IDEA 2018.2.6

springboot: 2.0.7.RELEASE

jdk: 1.8.0_192

maven: 3.6.0

mybatis: 3.4.6

mybatis 简介

什么是 MyBatis ?

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

What is MyBatis-Spring?

MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。 使用这个类库中的类, Spring 将会加载必要的 MyBatis 工厂类和 session 类。 这个类库也提供一个简单的方式来注入 MyBatis 数据映射器和 SqlSession 到业务层的 bean 中。 而且它也会处理事务, 翻译 MyBatis 的异常到 Spring 的 DataAccessException 异常(数据访问异常,译者注)中。最终,它并 不会依赖于 MyBatis,Spring 或 MyBatis-Spring 来构建应用程序代码。

mybatis的常用配置

设置参数

描述

有效值

默认值

cacheEnabled

全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存。

true | false

true

lazyLoadingEnabled

延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。

true | false

false

aggressiveLazyLoading

当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载(参考lazyLoadTriggerMethods).

true | false

false (true in ≤3.4.1)

multipleResultSetsEnabled

是否允许单一语句返回多结果集(需要兼容驱动)。

true | false

true

useColumnLabel

使用列标签代替列名。不同的驱动在这方面会有不同的表现, 具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果。

true | false

true

useGeneratedKeys

允许 JDBC 支持自动生成主键,需要驱动兼容。 如果设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工作(比如 Derby)。

true | false

False

autoMappingBehavior

指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射;PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套)。

NONE, PARTIAL, FULL

PARTIAL

autoMappingUnknownColumnBehavior

指定发现自动映射目标未知列(或者未知属性类型)的行为。NONE: 不做任何反应WARNING: 输出提醒日志 ('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior'的日志等级必须设置为 WARN)FAILING: 映射失败 (抛出 SqlSessionException)

NONE, WARNING, FAILING

NONE

defaultExecutorType

配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新。

SIMPLE REUSE BATCH

SIMPLE

defaultStatementTimeout

设置超时时间,它决定驱动等待数据库响应的秒数。

任意正整数

Not Set (null)

defaultFetchSize

为驱动的结果集获取数量(fetchSize)设置一个提示值。此参数只可以在查询设置中被覆盖。

任意正整数

Not Set (null)

safeRowBoundsEnabled

允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为false。

true | false

False

safeResultHandlerEnabled

允许在嵌套语句中使用分页(ResultHandler)。如果允许使用则设置为false。

true | false

True

mapUnderscoreToCamelCase

是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。

true | false

False

localCacheScope

MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。 默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。

SESSION | STATEMENT

SESSION

jdbcTypeForNull

当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。

JdbcType 常量. 大多都为: NULL, VARCHAR and OTHER

OTHER

lazyLoadTriggerMethods

指定哪个对象的方法触发一次延迟加载。

用逗号分隔的方法列表。

equals,clone,hashCode,toString

defaultScriptingLanguage

指定动态 SQL 生成的默认语言。

一个类型别名或完全限定类名。

org.apache.ibatis.scripting.xmltags.XMLLanguageDriver

defaultEnumTypeHandler

指定 Enum 使用的默认 TypeHandler 。 (从3.4.5开始)

一个类型别名或完全限定类名。

org.apache.ibatis.type.EnumTypeHandler

callSettersOnNulls

指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这对于有 Map.keySet() 依赖或 null 值初始化的时候是有用的。注意基本类型(int、boolean等)是不能设置成 null 的。

true | false

false

returnInstanceForEmptyRow

当返回行的所有列都是空时,MyBatis默认返回null。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集 (i.e. collectioin and association)。(从3.4.2开始)

true | false

false

logPrefix

指定 MyBatis 增加到日志名称的前缀。

任何字符串

Not set

logImpl

指定 MyBatis 所用日志的具体实现,未指定时将自动查找。

SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING

Not set

proxyFactory

指定 Mybatis 创建具有延迟加载能力的对象所用到的代理工具。

CGLIB | JAVASSIST

JAVASSIST (MyBatis 3.3 or above)

vfsImpl

指定VFS的实现

自定义VFS的实现的类全限定名,以逗号分隔。

Not set

useActualParamName

允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的工程必须采用Java 8编译,并且加上-parameters选项。(从3.4.1开始)

true | false

true

configurationFactory

指定一个提供Configuration实例的类。 这个被返回的Configuration实例用来加载被反序列化对象的懒加载属性值。 这个类必须包含一个签名方法static Configuration getConfiguration(). (从 3.2.3 版本开始)

类型别名或者全类名.

Not set

Mybatis对应的jdbcType数据类型

类型处理器

Java 类型

JDBC 类型

BooleanTypeHandler

java.lang.Boolean, boolean

数据库兼容的 BOOLEAN

ByteTypeHandler

java.lang.Byte, byte

数据库兼容的 NUMERIC 或 BYTE

ShortTypeHandler

java.lang.Short, short

数据库兼容的 NUMERIC 或 SHORT INTEGER

IntegerTypeHandler

java.lang.Integer, int

数据库兼容的 NUMERIC 或 INTEGER

LongTypeHandler

java.lang.Long, long

数据库兼容的 NUMERIC 或 LONG INTEGER

FloatTypeHandler

java.lang.Float, float

数据库兼容的 NUMERIC 或 FLOAT

DoubleTypeHandler

java.lang.Double, double

数据库兼容的 NUMERIC 或 DOUBLE

BigDecimalTypeHandler

java.math.BigDecimal

数据库兼容的 NUMERIC 或 DECIMAL

StringTypeHandler

java.lang.String

CHAR, VARCHAR

ClobReaderTypeHandler

java.io.Reader

-

ClobTypeHandler

java.lang.String

CLOB, LONGVARCHAR

NStringTypeHandler

java.lang.String

NVARCHAR, NCHAR

NClobTypeHandler

java.lang.String

NCLOB

BlobInputStreamTypeHandler

java.io.InputStream

-

ByteArrayTypeHandler

byte[]

数据库兼容的字节流类型

BlobTypeHandler

byte[]

BLOB, LONGVARBINARY

DateTypeHandler

java.util.Date

TIMESTAMP

DateOnlyTypeHandler

java.util.Date

DATE

TimeOnlyTypeHandler

java.util.Date

TIME

SqlTimestampTypeHandler

java.sql.Timestamp

TIMESTAMP

SqlDateTypeHandler

java.sql.Date

DATE

SqlTimeTypeHandler

java.sql.Time

TIME

ObjectTypeHandler

Any

OTHER 或未指定类型

EnumTypeHandler

Enumeration Type

VARCHAR-任何兼容的字符串类型,存储枚举的名称(而不是索引)

EnumOrdinalTypeHandler

Enumeration Type

任何兼容的 NUMERIC 或 DOUBLE 类型,存储枚举的索引(而不是名称)

InstantTypeHandler

java.time.Instant

TIMESTAMP

LocalDateTimeTypeHandler

java.time.LocalDateTime

TIMESTAMP

LocalDateTypeHandler

java.time.LocalDate

DATE

LocalTimeTypeHandler

java.time.LocalTime

TIME

OffsetDateTimeTypeHandler

java.time.OffsetDateTime

TIMESTAMP

OffsetTimeTypeHandler

java.time.OffsetTime

TIME

ZonedDateTimeTypeHandler

java.time.ZonedDateTime

TIMESTAMP

YearTypeHandler

java.time.Year

INTEGER

MonthTypeHandler

java.time.Month

INTEGER

YearMonthTypeHandler

java.time.YearMonth

VARCHAR or LONGVARCHAR

JapaneseDateTypeHandler

java.time.chrono.JapaneseDate

DATE

搭建项目

  • pom.xml
<?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">

    <artifactId>spring-boot-mybatis</artifactId>
    <groupId>com.andy</groupId>
    <version>1.0.7.RELEASE</version>
    <modelVersion>4.0.0</modelVersion>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>io.spring.platform</groupId>
                <artifactId>platform-bom</artifactId>
                <version>Cairo-SR6</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>


    <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.3.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>


    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.0.3.RELEASE</version>
                <configuration>
                    <!--<mainClass>${start-class}</mainClass>-->
                    <layout>ZIP</layout>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>
  • application.yml
server:
  port: 8081
  servlet:
    context-path: /
# spring-boot 连接 mysql 配置
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://host:3306/boot?useSSL=false&characterEncoding=utf8&allowMultiQueries=true
    username: root
    password: root

# mybatis-springBoot 配置
mybatis:
  configuration:
    # 全局映射器启用缓存
    cache-enabled: true
    # 当启用时,有延迟加载属性的对象在被调用时将会完全加载任意属性。否则,每种属性将会按需要加载。
    aggressive-lazy-loading: false
    # 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载
    lazy-loading-enabled: false
    # 对于批量更新操作缓存SQL以提高性能
    default-executor-type: reuse
    # 允许返回不同的结果集以达到通用的效果
    multiple-result-sets-enabled: true
    # 数据库执行超时时间
    default-statement-timeout: 25000
    # 打印sql语句
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    # 允许 JDBC 支持自动生成主键,需要驱动兼容。 如果设置为 true 则这个设置强制使用自动生成主键
    use-generated-keys: true
    # 设置但JDBC类型为空时,某些驱动程序 要指定值,default:OTHER,插入空值时不需要指定类型
    jdbc-type-for-null: null
    # 使用驼峰命名法转换字段
    map-underscore-to-camel-case: true
    # 指定 MyBatis 如何自动映射 数据基表的列 NONE:不隐射 PARTIAL:部分  FULL:全部
    auto-mapping-behavior: partial
    # 是否可以使用列的别名 (取决于驱动的兼容性) default:true
    use-column-label: true
    # 指定 Mybatis 创建具有延迟加载能力的对象所用到的代理工具。CGLIB|JAVASSIST, default(JAVASSIST)
    proxy-factory: CGLIB
    # 指定 MyBatis 增加到日志名称的前缀。任何字符串
    log-prefix: test
  mapper-locations: classpath:mybatis/mapper/*.xml
  type-aliases-package: com.andy.mapper
  executor-type: reuse
  • 启动类
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * <p>
 *
 * @author Leone
 * @since 2018-03-02
 **/
@MapperScan(basePackages = "com.andy.mybatis.mapper")
@SpringBootApplication
public class MybatisApplication {
    public static void main(String[] args) {
        SpringApplication.run(MybatisApplication.class, args);
    }
}
  • UserController.java
import com.andy.mybatis.entity.User;
import com.andy.mybatis.service.UserService;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

/**
 * <p>
 *
 * @author Leone
 * @since 2018-03-02
 **/
@RestController
@RequestMapping("/api/user")
public class UserController {

    @Resource
    private UserService userService;

    @PostMapping
    public int insert(@RequestBody User user) {
        return userService.insert(user);
    }

    @PostMapping("/batch")
    public int insertBatch(@RequestBody List<User> user) {
        return userService.insertBatch(user);
    }

    @DeleteMapping
    public int deleteById(@RequestParam Long userId) {
        return userService.delete(userId);
    }

    @DeleteMapping("/batch")
    public int deleteByIds(@RequestParam List<Long> userIds) {
        return userService.deleteByIds(userIds);
    }

    @GetMapping("/page")
    public List<User> selectList(@RequestParam Integer start, @RequestParam Integer size) {
        return userService.page(start, size);
    }

    @GetMapping("/{userId}")
    public User selectById(@PathVariable("userId") Long userId) {
        return userService.selectById(userId);
    }

    @PutMapping
    public int update(@RequestBody User user) {
        return userService.update(user);
    }

    @PutMapping("/batch")
    public int updateBatch(@RequestBody List<User> users) {
        return userService.updateBatch(users);
    }

}
  • User.java
import java.io.Serializable;
import java.util.Date;

/**
 * <p>
 *
 * @author Leone
 * @since 2018-03-02
 **/
public class User implements Serializable {

    private Long userId;

    private String account;

    private String password;

    private String description;

    private Integer age;

    private Date createTime;

    private boolean deleted;

    public User() {
    }

    public User(Long userId, String account, String password, String description, Integer age, Date createTime, Boolean deleted) {
        this.userId = userId;
        this.account = account;
        this.password = password;
        this.description = description;
        this.age = age;
        this.createTime = createTime;
        this.deleted = deleted;
    }

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public boolean isDeleted() {
        return deleted;
    }

    public void setDeleted(boolean deleted) {
        this.deleted = deleted;
    }
}
  • UserMapper.java
import com.andy.mybatis.entity.User;
import org.apache.ibatis.annotations.*;

import java.util.List;

/**
 * <p>
 *
 * @author Leone
 * @since 2018-03-02
 **/
@Mapper
public interface UserMapper {

    @Insert("insert into t_user(`account`, `password`, `age`, `description`, `deleted`, `create_time`) values (#{account},#{password},#{age},#{description},#{deleted},#{createTime})")
    int insert(User user);

    @Insert({"<script>" +
            "insert into t_user(`account`, `password`, `age`, `description`, `deleted`, `create_time`) values" +
            "<foreach collection=\"users\" item=\"user\" separator=\",\">" +
            "(#{user.account}, #{user.password}, #{user.age}, #{user.description}, #{user.deleted}, #{user.createTime}) " +
            "</foreach>" +
            "</script>"})
    int insertBatch(@Param("users") List<User> users);


    @Delete("delete from t_user where user_id = #{userId}")
    int deleteByUserId(@Param("userId") Long userId);

    @Delete("<script>" +
            "delete from t_user where user_id in " +
            "<foreach item='item' index='index' collection='userIds' open='(' separator=',' close=')'>" +
            "#{item}" +
            "</foreach>" +
            "</script>")
    int deleteByUserIds(@Param("userIds") List<Long> userIds);


    @Select("select * from t_user where user_id = #{userId}")
    User findByUserId(@Param("userId") Long userId);

    @Select("select * from t_user limit ${start}, ${size}")
    List<User> page(@Param("start") int start, @Param("size") int size);


    @Update({"update t_user set account=#{user.account}, password=#{user.password}, age=#{user.age}, description=#{user.description}, create_time=#{user.createTime, jdbcType=TIMESTAMP}, deleted=#{user.deleted} where user_id = #{user.userId}"})
    int update(@Param("user") User user);

    @Update({"<script>" +
            "<foreach collection=\"users\" item=\"item\" separator=\";\">" +
            " update t_user set" +
            " account=#{item.account}," +
            " password=#{item.password}," +
            " age=#{item.age}," +
            " description=#{item.description}," +
            " create_time=#{item.createTime}," +
            " deleted=#{item.deleted}" +
            " where user_id=#{item.userId}" +
            "</foreach>" +
            "</script>"})
    int updateBatch(@Param("users") List<User> users);

}
  • UserService.java
import com.andy.mybatis.entity.User;
import com.andy.mybatis.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
 * <p>
 *
 * @author Leone
 * @since 2018-03-02
 **/
@Slf4j
@Service
public class UserService {

    @Resource
    private UserMapper userMapper;


    /**
     * 插入
     *
     * @param user
     * @return
     */
    public int insert(User user) {
        return userMapper.insert(user);
    }

    /**
     * 批量插入
     *
     * @param user
     * @return
     */
    public int insertBatch(List<User> user) {
        return userMapper.insertBatch(user);
    }


    /**
     * 更新
     *
     * @param user
     * @return
     */
    public int update(User user) {
        return userMapper.update(user);
    }

    /**
     * 批量更新
     *
     * @param users
     * @return
     */
    public int updateBatch(List<User> users) {
        return userMapper.updateBatch(users);
    }


    /**
     * 分页
     *
     * @param start
     * @param size
     * @return
     */
    public List<User> page(Integer start, Integer size) {
        return userMapper.page(start, size);
    }


    /**
     * 根据主键删除
     *
     * @param userId
     */
    public int delete(Long userId) {
        return userMapper.deleteByUserId(userId);
    }

    /**
     * 批量删除
     *
     * @param userIds
     */
    public int deleteByIds(List<Long> userIds) {
        return userMapper.deleteByUserIds(userIds);
    }

    public User selectById(Long userId) {
        return userMapper.findByUserId(userId);
    }
}

传送门