zoukankan      html  css  js  c++  java
  • SpringBoot | 第三十五章:Mybatis的集成和使用

    前言

    最近收到公众号留言说,单纯的Mybatis的集成和使用。前面在第九章:Mybatis-plus的集成和使用介绍了基于mybatis-plus的集成和使用。后者也只是对mybatis进行了功能增强,原本的用法都是没有变化的。那今天就来简单介绍了如何springboot中如何集成和使用Mybatis吧。

    SpringBoot的集成和使用

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

    这里介绍基于xml注解两种方式进行配置。同时使用mybatis-spring-boot-starter进行集成。

    这里选用的mybatis-spring-boot-starter版本为:1.3.2
    对应Mybatis版本为:3.4.6

    通用配置

    两种方式都引入一下的pom配置:

    <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>
            </dependency>
    

    这里以user表为例子,数据库为mysql

    DROP TABLE IF EXISTS `user`;
    CREATE TABLE `user` (
      `id` bigint(20) DEFAULT NULL COMMENT '唯一标示',
      `code` varchar(20) DEFAULT NULL COMMENT '编码',
      `name` varchar(64) DEFAULT NULL COMMENT '名称',
      `status` char(1) DEFAULT '1' COMMENT '状态 1启用 0 停用',
      `gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
      `gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间'
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    

    实体类User为:

    /**
     * <p>
     * 
     * </p>
     *
     * @author oKong
     * @since 2018-12-02
     */
    @Data
    @Accessors(chain = true)
    public class User implements Serializable{
         /**
         * 
         */
        private static final long serialVersionUID = 1779270373648636358L;
        /**
         * 唯一标示
         */
        private Long id;
        /**
         * 编码
         */
        private String code;
        /**
         * 名称
         */
        private String name;
        
        /**
         * 状态1 启用 0 停用
         */
        private StatusEnum status;
        /**
         * 创建时间
         */
        private Date gmtCreate;
        /**
         * 修改时间
         */
        private Date gmtModified;
    }
    

    状态枚举类StatusEnum

    public enum StatusEnum {
        
        DISABLE,
        ENABLE;
    
    }
    

    配置文件:application.properties

    
    # 实体别名
    mybatis.type-aliases-package=cn.lqdev.learning.springboot.chapter35.biz.entity
    
    # 数据库配置
    spring.datasource.driverClassName=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/learning?useUnicode=true&characterEncoding=utf-8
    spring.datasource.username=root
    spring.datasource.password=
    
    spring.profiles.active=anno
    

    启动类

    /**
     * mybaits集成
     * @author oKong
     *
     */
    @SpringBootApplication
    @Slf4j
    public class MybatisApplication {
    
        public static void main(String[] args) throws Exception {
            SpringApplication.run(MybatisApplication.class, args);
            log.info("spring-boot-mybatis-chapter35启动!");
        }
    }
    

    注解方式

    0.创建注解版的mapper:

    UserMapper.java

    /**
     * 注解配置
     * @author okong
     *
     */
    public interface UserMapper {
        //配置返回的字段类型,这里配置了创建日期和修改日期自动
        @Select("select * from user where id = #{id}")
        @Results({
            @Result(column = "gmt_create",property = "gmtCreate",jdbcType=JdbcType.DATE),
            @Result(column = "gmt_modified",property = "gmtModified",jdbcType=JdbcType.DATE)
        })
        User queryOne(Long id);
        
        // 枚举类 默认是使用 EnumTypeHandler 处理类,即使用枚举name作为值
        //status 为枚举类 也可以直接指定了 typeHandler类 作为处理类 ,如:#{status,typeHandler=org.apache.ibatis.type.EnumOrdinalTypeHandler}
        //还可以在sqlFactory 直接使用  TypeHandlerRegistry  进行注册 详看;MybatisConfig 类
        //最简单:自定义 ConfigurationCustomizer 了进行设置 详看;MybatisConfig 类
        @Insert("insert into user(code,name,status) values(#{code},#{name}, #{status})")
        //以下配置会对user对象进行id赋值
        @Options(keyProperty="id",keyColumn="id",useGeneratedKeys=true)
        int insert(User user);
        
        @Update("update user set code=#{code}, name = #{name}, status = #{status} where id=#{id}")
        void update(User user);
        
        @Delete("delete from user where id=#{id}")
        void delete(Long id);
        
        @Select("select * from user where code = #{code}")
        @Results({
            @Result(column = "gmt_create",property = "gmtCreate",jdbcType=JdbcType.DATE),
            @Result(column = "gmt_modified",property = "gmtModified",jdbcType=JdbcType.DATE)
        })    
        List<User> queryByParams(@Param("code")String code);
    }
    

    简单对以上相关注解进行说明下:

    • @Select 是查询类的注解,所有的查询均使用这个
    • @Result 修饰返回的结果集,关联实体类属性和数据库字段一一对应,如果实体类属性和数据库属性名保持一致,就不需要这个属性来修饰。
    • @Insert 插入数据库使用,直接传入实体类会自动解析属性到对应的值
    • @Update 负责修改,也可以直接传入对象
    • @delete 负责删除
    • @Options 映射语句的属性,如新增时需要返回自增的ID时:@Options(keyProperty="id",keyColumn="id",useGeneratedKeys=true)

    具体的可以去官网查阅:http://www.mybatis.org/mybatis-3/zh/java-api.html

    映射器注解

    2.指定mapper扫描包路径,使用注解@MapperScan

    /**
     * mybaits配置
     * @author oKong
     *
     */
    @Configuration
    @MapperScan("cn.lqdev.learning.springboot.chapter35.biz.mapper")//mapper地址
    public class MybatisConfig {
         
    }
    

    注意:若使用Druid进行数据连接池管理,也可以在此类中进行DataSource的相关配置。

    3.编写测试类进行测试。

    /**
     * 测试类
     * @author oKong
     *
     */
    @RunWith(SpringRunner.class)
    @SpringBootTest
    @ActiveProfiles("anno")
    @Slf4j
    public class UserMapperTest {
        
        @Autowired
        UserMapper userMpper;
        
        @Test
        public void testInsert() {
            User user = new User();
            user.setCode("002");
            user.setName("name002");
            user.setStatus(StatusEnum.ENABLE);
            
            //新增
            userMpper.insert(user);
        }
        
        @Test
        public void testQueryOne() {
            User user = userMpper.queryOne(1L);
            log.info("id为1的查询结果为:{}", user);
        }
        
        @Test
        public void testUpdate() {
            User user = new User();
            user.setCode("002");
            user.setName("testUpdate");
            user.setStatus(StatusEnum.ENABLE);
            userMpper.insert(user);
            
            User userUpd = userMpper.queryOne(user.getId());
            userUpd.setName("更新name");
            userMpper.update(userUpd);
            
            Assert.assertEquals("更新失败",userUpd.getName(), userMpper.queryOne(user.getId()).getName());
        }
        
        @Test
        public void testParamSelect() {
            String code = "002";
            List<User> list = userMpper.queryByParams(code);
            
            log.info("查询编码为002,查询结果为:{}条,结果集为:{}",list.size(), Arrays.toString(list.toArray()));
        }
    
    }
    

    运行测试用例后,就可以看见效果了。

    具体控制台输出就输出了,可下载源码自行测试下。

    xml方式

    0.配置xml版的mapper。

    /**
     * xml映射
     * @author oKong
     *
     */
    public interface UserXmlMapper {
    
        User queryOne(Long id);
        
        int insert(User user);
        
        void update(User user);
        
        void delete(Long id);
            
        List<User> queryByParams(@Param("code")String code);
    }
    

    没啥区别,就是讲sql语句放入到了xml中进行编写而已。

    1.编写mapper.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="cn.lqdev.learning.springboot.chapter35.biz.mapper.UserXmlMapper">
       
        <!-- 配置返回类型 -->
       <resultMap type="User" id="userResultMap">
          <result column="id" property="id"/>
          <result column="code" property="code"/>
          <result column="name" property="name"/>
          <result column="status" property="status"/>
          <result column="gmt_create" property="gmtCreate" jdbcType="DATE"/>
          <result column="gmt_modified" property="gmtModified" jdbcType="DATE"/>
       
       </resultMap>
    
        <!-- 通用查询结果列 -->
        <sql id="Base_Column_List">
            id, code, name, status, gmt_create, gmt_modified
        </sql>
        
        <select id="queryOne" resultMap="userResultMap">
          select 
          <include refid="Base_Column_List"></include>
          from user
          where id = #{id}
        </select>
    
        <!-- 返回主键id -->
        <insert id="insert" parameterType="User" keyProperty="id" useGeneratedKeys="true">
            insert into user(code,name,status) values(#{code},#{name}, #{status})
            <!--  insert into user(code,name,status) values(#{code},#{name}, #{status, typeHandler=org.apache.ibatis.type.EnumOrdinalTypeHandler}) -->
        </insert>
        
        <update id="update"  parameterType="User">
           update user set code=#{code}, name = #{name}, status = #{status} where id=#{id}
        </update>
        
        <delete id="delete">
           delete from user where id=#{id}
        </delete>
        
        <select id="queryByParams" resultMap="userResultMap">
          select 
          <include refid="Base_Column_List"></include>
          from user
           where code = #{code}
        </select>
    </mapper>
    

    2.mybatis配置文件。

    mybatis-config.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <!--全局配置-->
        <settings>
            <!-- 这个配置使全局的映射器启用或禁用缓存 -->
            <setting name="cacheEnabled" value="true"/>
            <!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载 -->
            <setting name="lazyLoadingEnabled" value="false"/>
            <setting name="multipleResultSetsEnabled" value="true"/>
            <setting name="useColumnLabel" value="true"/>
            <setting name="defaultExecutorType" value="REUSE"/>
            <setting name="defaultStatementTimeout" value="25000"/>
            <setting name="aggressiveLazyLoading" value="true"/>
            <setting name="mapUnderscoreToCamelCase" value="true"/>
        </settings>
        <typeHandlers>
           <!-- 枚举类 -->
           <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler"
             javaType="cn.lqdev.learning.springboot.chapter35.biz.entity.StatusEnum"/>
        </typeHandlers>
        
    </configuration>
    

    对于特殊的类型,可以通过typeHandlers进行配置。稍后章节也会讲解想通过其他的方式进行配置。

    3.创建xml方式配置文件:application-xml.properties,配置xml和config的路径地址

    # 配置mapper.xml和mybatis-config.xml路径
    mybatis.config-location=classpath:mybatis/mybatis-config.xml
    mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
    

    4.编写测试类:UserXmlMapperTest.java
    此类和UserMapperTest类似的,唯一区别就是制定了运行环境变量为:xml

    @ActiveProfiles("xml")
    

    枚举类型处理器配置

    在实体对象中我们设置了枚举类型:StatusEnum。在mybatis中对于枚举的默认配置是由EnumTypeHandler处理类进行处理的,其会默认使用name进行赋值。同时mybatis还提供了一个EnumOrdinalTypeHandler处理类,其是根据枚举的索引值进行赋值的。

    注册类型处理类有很多中方式,但每一种方式最后都是通过TypeHandlerRegistry类进行处理的,这里讲解下通过多种方式进行配置。

    • 配置文件中新增属性:mybatis.type-handlers-package:配置处理类的路径。
    # 类型处理类
    mybatis.type-handlers-package=cn.lqdev.learning.springboot.chapter35.config
    

    处理类示例:CustomEnumOrdinalTypeHandler.java。这里直接继承EnumOrdinalTypeHandler进行自定义。

    /**
     * 
     * @author oKong
     *
     */
    //枚举索引处理类
    @MappedTypes(value = { StatusEnum.class })
    public class CustomEnumOrdinalTypeHandler<E extends Enum<E>> extends EnumOrdinalTypeHandler<E>{
    
        public CustomEnumOrdinalTypeHandler(Class<E> type) {
            super(type);
        }
    }
    

    其中,@MapperType指定了哪些类型指定此处理类的。

    • 自定义ConfigurationCustomizer类进行配置(推荐)。
        /**
         * 
         * <p>函数名称:  ConfigurationCustomizer      </p>
         * <p>功能说明: 自定义相关注册器
         *
         * </p>
         *<p>参数说明:</p>
         * @return
         *
         * @date   创建时间:2018年12月2日
         * @author 作者:oKong
         */
        @Bean
        public ConfigurationCustomizer configurationCustomizer() {
            ConfigurationCustomizer config = new ConfigurationCustomizer() {
                
                @Override
                public void customize(org.apache.ibatis.session.Configuration configuration) {
    //                TypeAliasRegistry typeAliasRegistry = configuration.getTypeAliasRegistry();
                    // mapper接口注册器
    //                MapperRegistry mapperRegistry = configuration.getMapperRegistry();
                    // 类型处理器
                    TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
                    typeHandlerRegistry.register(StatusEnum.class, EnumOrdinalTypeHandler.class);
                }
            };
            
            return config;
        }
    
    • 通过SqlSessionFactory来获取TypeHandlerRegistry进行配置。
        @Autowired
        SqlSessionFactory sqlSessionFactory;
        
        @PostConstruct
        public void registerTypeHandler() {
            TypeHandlerRegistry registry = sqlSessionFactory.getConfiguration().getTypeHandlerRegistry();
            registry.register(StatusEnum.class, EnumOrdinalTypeHandler.class);
        }
    

    以上三种都可以进行相关类型的处理类配置,建议直接使用第二种。

    完整的MybatisConfig类:

    /**
     * mybaits配置
     * @author oKong
     *
     */
    @Configuration
    @MapperScan("cn.lqdev.learning.springboot.chapter35.biz.mapper")//mapper地址
    public class MybatisConfig {
        
        //使用 SqlSessionFactory 类获取 TypeHandlerRegistry 进行注册
    //    @Autowired
    //    SqlSessionFactory sqlSessionFactory;
    //    
    //    @PostConstruct
    //    public void registerTypeHandler() {
    //        TypeHandlerRegistry registry = sqlSessionFactory.getConfiguration().getTypeHandlerRegistry();
    //        registry.register(StatusEnum.class, EnumOrdinalTypeHandler.class);
    //    }
        
        /**
         * 
         * <p>函数名称:  ConfigurationCustomizer      </p>
         * <p>功能说明: 自定义相关注册器
         *
         * </p>
         *<p>参数说明:</p>
         * @return
         *
         * @date   创建时间:2018年12月2日
         * @author 作者:oKong
         */
        @Bean
        public ConfigurationCustomizer configurationCustomizer() {
            ConfigurationCustomizer config = new ConfigurationCustomizer() {
                
                @Override
                public void customize(org.apache.ibatis.session.Configuration configuration) {
    //                TypeAliasRegistry typeAliasRegistry = configuration.getTypeAliasRegistry();
                    // mapper接口注册器
    //                MapperRegistry mapperRegistry = configuration.getMapperRegistry();
                    // 类型处理器
                    TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
                    typeHandlerRegistry.register(StatusEnum.class, EnumOrdinalTypeHandler.class);
                }
            };
            
            return config;
        }
    }
    

    参考资料

    总结

    本章节主要简单介绍了mybatis集成的两种模式。两种模式各有特点,注解版适合简单快速的模式,而xml方式适合相对复杂的sql语句,写在xml中,可以进行统一修改,而不需要去修改java代码。对于原生使用mybatis而言,感觉也是比较简单的,就是写起语句比较麻烦,都需要手动去编写。对于代码生成器,大家可执行搜索相关材料下,大致看了下有点麻烦。所以还是选择一个脚手架吧,mybatis-plus是一个很好的选择。当然了其他的脚手架框架了,大家可自行根据实际情况进行抉择。前几天去看博客评论时,有人觉得开发本来就很累了还要学习这种小框架,我觉得吧,这些小框架可以节省多少繁琐的工作呀。让开发人员可以专注于业务代码,多美好的一件事情呀。将近两星期没有写,可能写的有些乱了,大家可以直接下载源码示例进行查看下,原本想分开两个工程进行讲解,感觉也没有必要,就合并在一起了,通过不同的环境配置进行切换,还请谅解呀!

    最后

    目前互联网上很多大佬都有SpringBoot系列教程,如有雷同,请多多包涵了。原创不易,码字不易,还希望大家多多支持。若文中有所错误之处,还望提出,谢谢。

    老生常谈

    • 个人QQ:499452441
    • 微信公众号:lqdevOps

    公众号

    个人博客:http://blog.lqdev.cn

    完整示例:https://github.com/xie19900123/spring-boot-learning/tree/master/chapter-35

    原文地址:http://blog.lqdev.cn/2018/12/03/springboot/chapter-thirty-five/

  • 相关阅读:
    laravel 服务容器,容器概念
    初识swoole
    一个小demo---递归计算子类下的某个值的总和
    微信支付の退款申请
    Box/Spout处理excel和csv
    mysql 获取指定日期的周/月开始 和 周/月结束
    时间字段规定模式获取
    异步服务器之心跳检测
    larave -- leftJoin IFNULL 链表查询
    Mac版Navicat破解
  • 原文地址:https://www.cnblogs.com/okong/p/springboot-thirty-five.html
Copyright © 2011-2022 走看看