完整代码参照:
https://github.com/biticcf/ocean-sea-platform.git
SpringBoot的便捷性就在于其xml配置文件非常少,几乎都可以用注解代替。
传统的Mybatis主要也是依赖于xml文件,那么当Mybatis遇上SpringBoot时,如何用注解取代其xml配置文件呢?
1,Mybatis的config.xml文件
mybatis_config.xml文件是Mybatis的条件配置文件,它有很多项,具体配置可参照下面代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN"
"http://ibatis.apache.org/dtd/ibatis-3-config.dtd">
<configuration>
<settings>
<!-- 全局映射器启用缓存 -->
<setting name="cacheEnabled" value="true" />
<!-- 查询时,关闭关联对象即时加载以提高性能 -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 设置关联对象加载的形态,此处为按需加载字段(加载字段由SQL指 定),不会加载关联表的所有字段,以提高性能 -->
<setting name="aggressiveLazyLoading" value="false" />
<!-- 对于未知的SQL查询,允许返回不同的结果集以达到通用的效果 -->
<setting name="multipleResultSetsEnabled" value="true" />
<!-- 允许使用列标签代替列名 -->
<setting name="useColumnLabel" value="true" />
<!-- 允许使用自定义的主键值(比如由程序生成的UUID 32位编码作为键值),数据表的PK生成策略将被覆盖 -->
<setting name="useGeneratedKeys" value="true" />
<!-- 给予被嵌套的resultMap以字段-属性的映射支持(NONE, PARTIAL, FULL) -->
<setting name="autoMappingBehavior" value="FULL" />
<!-- 配置默认的执行器,SIMPLE 执行器没有什么特别之处,REUSE 执行器重用预处理语句,BATCH 执行器重用语句和批量更新 -->
<setting name="defaultExecutorType" value="REUSE" />
<!-- 数据库超过180秒仍未响应则超时 -->
<setting name="defaultStatementTimeout" value="180" />
<!-- 是否启用下划线与驼峰式命名规则的映射(如first_name => firstName) -->
<setting name="mapUnderscoreToCamelCase" value="true" />
<setting name="defaultFetchSize" value="200" />
<!-- SESSION, STATEMENT -->
<setting name="localCacheScope" value="SESSION" />
<!-- NULL, VARCHAR, OTHER -->
<setting name="jdbcTypeForNull" value="OTHER" />
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString" />
<setting name="logPrefix" value="[mybatis]" />
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- 设置数据库类型 Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL六种数据库-->
<property name = "helperDialect" value = "mysql"/>
<!-- 设置为true时,会将RowBounds第一个参数offset当成pageNum页码使用 -->
<property name = "offsetAsPageNum" value = "false"/>
<!-- 设置为true时,使用RowBounds分页会进行count查询 -->
<property name = "rowBoundsWithCount" value = "true"/>
<!-- 设置为true时,如果pageSize = 0或者RowBounds.limit = 0就会查询出全部的结果 -->
<property name = "pageSizeZero" value = "false"/>
<!-- 禁用合理化时,如果pageNum < 1或pageNum > pages会返回空数据 -->
<property name = "reasonable" value = "false"/>
<!-- 支持通过Mapper接口参数来传递分页参数 -->
<property name = "supportMethodsArguments" value = "false"/>
<!-- always总是返回PageInfo类型,check检查返回类型是否为PageInfo,none返回Page -->
<property name = "returnPageInfo" value = "none"/>
</plugin>
</plugins>
</configuration>
要取代这个文件,我们可以引入MybatisAutoConfiguration配置文件
@Configuration
@MapperScan(basePackages = {"${mybatis.type-dao-package:com.biticcf.ocean.sea.domain.dao}"},
sqlSessionFactoryRef = "sqlSessionFactory")
@EnableTransactionManagement
@AutoConfigureOrder(-100)
@AutoConfigureAfter({MybatisAutoConfiguration.class})
public class DatasourceConfig {
...
}
然后即可启用MybatisProperties属性配置文件,使用yml对Mybatis属性进行配置:
这里要注意:
MybatisProperties文件里有两个配置参数项:
configLocation:这个是用来指定mybatis_config.xml文件地址;
configuration:这里是通过注解的方式自定义配置文件;
在这里如果配置了configLocation,那么configuration将不再起作用!
因此,我们为了通过配置文件来配置属性的话,configLocation一定不能配置!
接下来,我们通过yml来替换xml配置文件
mybatis:
# config-location: classpath:bean/mybatis/mybatis_config.xml
# mapper-locations: classpath:/bean/mybatis/mapping/*.xml
type-aliases-package: com.biticcf.ocean.sea.domain.dao.po
type-dao-package: com.biticcf.ocean.sea.domain.dao
executorType: REUSE
configuration:
cache-enabled: true
lazy-loading-enabled: true
aggressive-lazy-loading: false
multiple-result-sets-enabled: true
use-column-label: true
use-generated-keys: true
auto-mapping-behavior: FULL
default-executor-type: REUSE
default-statement-timeout: 180
map-underscore-to-camel-case: true
default-fetch-size: 200
local-cache-scope: SESSION
jdbc-type-for-null: OTHER
lazy-load-trigger-methods: equals,clone,hashCode,toString
log-prefix: [mybatis]
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
pagehelper:
helper-dialect: mysql
offset-as-page-num: false
row-bounds-with-count: true
page-size-zero: false
reasonable: false
support-methods-arguments: false
return-page-info: none
其中,mybatis.configuration对应了xml文件中的settings配置属性,mybatis.interceptors对应了xml文件中的plugins,这部功能只需要引入分页组件即可,代码如下:
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.10</version>
</dependency>
这样配置完毕,mybatis_config.xml就可以完全替换了。
2,Mybatis的mapper.xml文件
Mybatis的mapper.xml文件是数据库映射文件,里面包含了数据库相关定义、缓存相关定义、数据操作sql定义等,具体代码如下:
<?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.beyonds.phoenix.coral.domain.dao.DemoDAO">
<sql id="tableColumns">
ID,
GOODS_CODE,
GOODS_SN,
STATUS,
CREATE_TIME,
UPDATE_TIME,
VERSION
</sql>
<insert id="insert"
parameterType="com.beyonds.phoenix.coral.domain.dao.po.DemoPo"
useGeneratedKeys="true"
keyProperty="id">
INSERT INTO WD_DEMO_INFO
(
GOODS_CODE,
GOODS_SN,
STATUS,
CREATE_TIME,
UPDATE_TIME,
VERSION
)
VALUES
(
#{goodsCode},
#{goodsSn},
0,
now(),
now(),
0
)
</insert>
<insert id="batchInsert"
parameterType="com.beyonds.phoenix.coral.domain.dao.po.DemoPo"
useGeneratedKeys="true"
keyProperty="id">
INSERT INTO WD_DEMO_INFO
(
GOODS_CODE,
GOODS_SN,
STATUS,
CREATE_TIME,
UPDATE_TIME,
VERSION
)
VALUES
<foreach collection="list" item="item" index="index" separator="," >
(
#{item.goodsCode},
#{item.goodsSn},
0,
now(),
now(),
0
)
</foreach>
</insert>
</mapper>
下面,我们来替换掉这个文件。
2.1,在配置中去掉xml路径
mybatis:
# config-location: classpath:bean/mybatis/mybatis_config.xml
# mapper-locations: classpath:/bean/mybatis/mapping/*.xml
type-aliases-package: com.biticcf.ocean.sea.domain.dao.po
type-dao-package: com.biticcf.ocean.sea.domain.dao
2.2,在DAO接口中实现二级缓存
@CacheNamespace(eviction = LruCache.class, flushInterval = 60000L, size = 1024, readWrite = true)
@Mapper
public interface DemoDAO {
...
}
注意,此时的DAO接口一定要加上@Mapper注解。
2.3,在DAO接口中实现字段映射
/**
* 根据id查询
* @param id ID值
* @return 查询结果
*/
@Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
@Results(id = "demoMap", value = {
@Result(property = "id", column = "id", id = true, javaType = Long.class, jdbcType = JdbcType.BIGINT),
@Result(property = "goodsCode", column = "GOODS_CODE", javaType = String.class, jdbcType = JdbcType.VARCHAR),
@Result(property = "goodsSn", column = "GOODS_SN", javaType = String.class, jdbcType = JdbcType.VARCHAR),
@Result(property = "status", column = "STATUS", javaType = Byte.class, jdbcType = JdbcType.TINYINT),
@Result(property = "createTime", column = "CREATE_TIME", javaType = Date.class, jdbcType = JdbcType.TIMESTAMP),
@Result(property = "updateTime", column = "UPDATE_TIME", javaType = Date.class, jdbcType = JdbcType.TIMESTAMP),
@Result(property = "version", column = "VERSION", javaType = Integer.class, jdbcType = JdbcType.INTEGER)
})
@Select("SELECT * FROM WD_DEMO_INFO WHERE ID = #{id}")
DemoPo queryById(@Param("id") long id);
这里,@Results(id = "demoMap")定义了一个名称是demoMap映射Map,在当前DAO文件(Namespace)中的其他sql下可以使用;
@Options是用来定义如何使用缓存的。
2.4,在DAO接口中使用Map映射
/**
* +查询列表
* @return 查询结果
*/
@Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
@Select("SELECT * FROM WD_DEMO_INFO ORDER BY ID DESC")
@ResultMap(value = {"demoMap"})
List<DemoPo> queryList();
2.5,在DAO接口中使用SqlProvider
SqlProvider是用来实现复杂sql语句和动态sql语句的。
/**
* +保存一条记录
* @param demoPo 数据记录
* @return 保存成功条数
*/
@Options(useCache = true, flushCache = Options.FlushCachePolicy.TRUE, useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
@InsertProvider(type = DemoSqlProvider.class, method = "insert")
int insert(DemoPo demoPo);
其中,DemoSqlProvider实现如下:
public class DemoSqlProvider {
/**
* +添加数据sql
* @param demoPo 传入对象值
* @return 拼成的sql
*/
public String insert(DemoPo demoPo) {
return new SQL() {
{
INSERT_INTO("`WD_DEMO_INFO`");
INTO_COLUMNS("`GOODS_CODE`", "`GOODS_SN`", "`STATUS`", "`CREATE_TIME`", "`UPDATE_TIME`", "`VERSION`");
INTO_VALUES("#{goodsCode}", "#{goodsSn}", "0", "now()", "now()", "0");
}
}.toString();
}
/**
* +批量添加数据sql
* @param map 批量数据
* @return 拼成的sql
*/
public String inserts(Map<String, List<DemoPo>> map) {
List<DemoPo> demoList = map.get("list");
if (demoList == null || demoList.isEmpty()) {
return null;
}
StringBuilder sql = new StringBuilder("");
sql.append("INSERT INTO `WD_DEMO_INFO`");
sql.append("(`GOODS_CODE`, `GOODS_SN`, `STATUS`, `CREATE_TIME`, `UPDATE_TIME`, `VERSION`)");
sql.append("VALUES");
for (int i = 0; i < demoList.size(); i++) {
sql.append("(#{list[" + i + "].goodsCode}, #{list[" + i + "].goodsSn}, 0, now(), now(), 0),");
}
sql.deleteCharAt(sql.length() - 1);
sql.append(";");
return sql.toString();
}
}
在这里需要注意的是,SqlProvider的方法中,只能有一个参数,可以是Map(或者Map等价的普通bean)。Mybatis会自动把多个参数包装成Map,用@Param("id")的value作为键值。
另外,目前Mybatis提供的内建SQL()方法,还没提供批量添加的功能,需要手动拼装,如上面的inserts方法。
完整代码请参照https://github.com/biticcf/ocean-sea-platform.git
-End-