Spring Boot入门系列之:三、Spring Boot整合Mybatis

本文介绍如何在Spring Boot环境中集成MyBatis框架,包括配置、开发工具、依赖管理和基本CRUD操作示例。

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 | falsetrue
lazyLoadingEnabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。true | falsefalse
aggressiveLazyLoading当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载(参考lazyLoadTriggerMethods).true | falsefalse (true in ≤3.4.1)
multipleResultSetsEnabled是否允许单一语句返回多结果集(需要兼容驱动)。true | falsetrue
useColumnLabel使用列标签代替列名。不同的驱动在这方面会有不同的表现, 具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果。true | falsetrue
useGeneratedKeys允许 JDBC 支持自动生成主键,需要驱动兼容。 如果设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工作(比如 Derby)。true | falseFalse
autoMappingBehavior指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射;PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套)。NONE, PARTIAL, FULLPARTIAL
autoMappingUnknownColumnBehavior指定发现自动映射目标未知列(或者未知属性类型)的行为。NONE: 不做任何反应WARNING: 输出提醒日志 ('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior'的日志等级必须设置为 WARN)FAILING: 映射失败 (抛出 SqlSessionException)NONE, WARNING, FAILINGNONE
defaultExecutorType配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新。SIMPLE REUSE BATCHSIMPLE
defaultStatementTimeout设置超时时间,它决定驱动等待数据库响应的秒数。任意正整数Not Set (null)
defaultFetchSize为驱动的结果集获取数量(fetchSize)设置一个提示值。此参数只可以在查询设置中被覆盖。任意正整数Not Set (null)
safeRowBoundsEnabled允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为false。true | falseFalse
safeResultHandlerEnabled允许在嵌套语句中使用分页(ResultHandler)。如果允许使用则设置为false。true | falseTrue
mapUnderscoreToCamelCase是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。true | falseFalse
localCacheScopeMyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。 默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。SESSION | STATEMENTSESSION
jdbcTypeForNull当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。JdbcType 常量. 大多都为: NULL, VARCHAR and OTHEROTHER
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 | falsefalse
returnInstanceForEmptyRow当返回行的所有列都是空时,MyBatis默认返回null。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集 (i.e. collectioin and association)。(从3.4.2开始)true | falsefalse
logPrefix指定 MyBatis 增加到日志名称的前缀。任何字符串Not set
logImpl指定 MyBatis 所用日志的具体实现,未指定时将自动查找。SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGINGNot set
proxyFactory指定 Mybatis 创建具有延迟加载能力的对象所用到的代理工具。CGLIB | JAVASSISTJAVASSIST (MyBatis 3.3 or above)
vfsImpl指定VFS的实现自定义VFS的实现的类全限定名,以逗号分隔。Not set
useActualParamName允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的工程必须采用Java 8编译,并且加上-parameters选项。(从3.4.1开始)true | falsetrue
configurationFactory指定一个提供Configuration实例的类。 这个被返回的Configuration实例用来加载被反序列化对象的懒加载属性值。 这个类必须包含一个签名方法static Configuration getConfiguration(). (从 3.2.3 版本开始)类型别名或者全类名.Not set

Mybatis对应的jdbcType数据类型

类型处理器Java 类型JDBC 类型
BooleanTypeHandlerjava.lang.Boolean, boolean数据库兼容的 BOOLEAN
ByteTypeHandlerjava.lang.Byte, byte数据库兼容的 NUMERIC 或 BYTE
ShortTypeHandlerjava.lang.Short, short数据库兼容的 NUMERIC 或 SHORT INTEGER
IntegerTypeHandlerjava.lang.Integer, int数据库兼容的 NUMERIC 或 INTEGER
LongTypeHandlerjava.lang.Long, long数据库兼容的 NUMERIC 或 LONG INTEGER
FloatTypeHandlerjava.lang.Float, float数据库兼容的 NUMERIC 或 FLOAT
DoubleTypeHandlerjava.lang.Double, double数据库兼容的 NUMERIC 或 DOUBLE
BigDecimalTypeHandlerjava.math.BigDecimal数据库兼容的 NUMERIC 或 DECIMAL
StringTypeHandlerjava.lang.StringCHAR, VARCHAR
ClobReaderTypeHandlerjava.io.Reader-
ClobTypeHandlerjava.lang.StringCLOB, LONGVARCHAR
NStringTypeHandlerjava.lang.StringNVARCHAR, NCHAR
NClobTypeHandlerjava.lang.StringNCLOB
BlobInputStreamTypeHandlerjava.io.InputStream-
ByteArrayTypeHandlerbyte[]数据库兼容的字节流类型
BlobTypeHandlerbyte[]BLOB, LONGVARBINARY
DateTypeHandlerjava.util.DateTIMESTAMP
DateOnlyTypeHandlerjava.util.DateDATE
TimeOnlyTypeHandlerjava.util.DateTIME
SqlTimestampTypeHandlerjava.sql.TimestampTIMESTAMP
SqlDateTypeHandlerjava.sql.DateDATE
SqlTimeTypeHandlerjava.sql.TimeTIME
ObjectTypeHandlerAnyOTHER 或未指定类型
EnumTypeHandlerEnumeration TypeVARCHAR-任何兼容的字符串类型,存储枚举的名称(而不是索引)
EnumOrdinalTypeHandlerEnumeration Type任何兼容的 NUMERIC 或 DOUBLE 类型,存储枚举的索引(而不是名称)
InstantTypeHandlerjava.time.InstantTIMESTAMP
LocalDateTimeTypeHandlerjava.time.LocalDateTimeTIMESTAMP
LocalDateTypeHandlerjava.time.LocalDateDATE
LocalTimeTypeHandlerjava.time.LocalTimeTIME
OffsetDateTimeTypeHandlerjava.time.OffsetDateTimeTIMESTAMP
OffsetTimeTypeHandlerjava.time.OffsetTimeTIME
ZonedDateTimeTypeHandlerjava.time.ZonedDateTimeTIMESTAMP
YearTypeHandlerjava.time.YearINTEGER
MonthTypeHandlerjava.time.MonthINTEGER
YearMonthTypeHandlerjava.time.YearMonthVARCHAR or LONGVARCHAR
JapaneseDateTypeHandlerjava.time.chrono.JapaneseDateDATE

搭建项目

  • 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);
    }
}

传送门

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值