1. 程式人生 > >SpringBoot | 第三十五章:Mybatis的整合和使用

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/