文章目录
MyBatis的配置文件包括两个大的部分, 一是基础配置文件,一个是映射文件。在mybatis中可以使用注解和XML文件来配置。
一、Mybatis配置
1.配置内容
mybatis是一个基于SqlSessionFactory构建的框架,用于生成的SqlSession接口的对象是mybatis操作的核心,构建SqlSessionFactory通过配置类(Configuration)来完成,在mybatis-spring-boot-starter,我们可以在application.properties中进行配置相关内容。
- settings:可以配置映射规则等(如自动映射,驼峰映射,执行器类型,缓存等内容)可参考mybatus官方网站
- typeAliases:使用类全限定名会比较长,可配置自定义的别名
- mappers: 映射器,提供SQL和POJO的映射关系。
- typeHandlers:类型处理器,一般不需要自定义,一般使用集中在枚举类型上,在 MyBatis 写入和读取数据库的过程中对于不同类型的数据进行自定义转换(对于 Java JavaType ,对于数据库则是 JdbcType)
- objectFactory: 在mybatis生成返回的POJO时会调用的工厂类,Mybatis默认为(DefaultObjectFactory),一般不需要配置
- plugins :有时候也称为拦截器,可以修改 MyBatis 底层的实现功能
- environments:数据库环境配置,可以配置数据库连接内容和事务,一般采用Spring进行配置
- databaseldProvider:可配置多类型数据库,不常用
- properties:属性文件在实际用用中一般采用Spring进行配置,如数据库源的配置
@Alias(value = "user")
public class User {
....
// 性别枚举,这里需要使用typeHandler进行转换(如下)
private SexEnum sex;
}
//使用typeHandler进行转换
@MappedJdbcTypes(JdbcType.INTEGER) // 声明JdbcType为整形
@MappedTypes(value = SexEnum.class) // 声明JavaType为SexEnum
public class SexTypeHandler extends BaseTypeHandler<SexEnum> {
// 通过列名读取性别
@Override
public SexEnum getNullableResult(ResultSet rs, String col) throws SQLException {
int sex = rs.getInt(col);
if (sex != 1 && sex != 2){
return null;
}
return SexEnum.getEnumById(sex);
}
// 通过下标读取性别
@Override
public SexEnum getNullableResult(ResultSet rs, int idx) throws SQLException {
int sex = rs.getInt(idx);
if (sex != 1 && sex != 2){
return null;
}
return SexEnum.getEnumById(sex);
}
// 通过存储过程读取性别
@Override
public SexEnum getNullableResult(CallableStatement cs, int idx) throws SQLException {
int sex = cs.getInt(idx);
if (sex != 1 && sex != 2){
return null;
}
return SexEnum.getEnumById(sex);
}
// 设置非空性别参数
@Override
public void setNonNullParameter(PreparedStatement ps, int idx, SexEnum sex, JdbcType jdbcType) throws SQLException {
ps.setInt(idx, sex.getId());
}
}
2. 配置application.yml
spring:
# 配置Mysql数据源
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://10.107.171.101:3306/ssm?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
username: root
password: 123456
# 指定druid数据库连接池
type: com.alibaba.druid.pool.DruidDataSource
druid:
min-idle: 10 # 最小连接池数量
max-active: 50 # 最大连接活动数
max-wait: 10000 # 最大连接活动数 ms
initial-size: 5 # 数据库连接池初始化连接数
# Mybatis配置
mybatis:
# MyBatis映射文件的匹配
mapper-locations: classpath:mapper/*.xml
# MyBatis扫描别名包,和注解@Alias 联用
type-aliases-package: com.cq3jk.demomybatis.entity
# 配置typeHandler的扫描包
type-handlers-package: com.cq3jk.demomybatis.typehandler
3、定义一个映射的接口
// 此接口不需要任何实现类,由一个xml文件去实现
// MyBatis 提供了一个对 Mapper 注解@Mapper
@Repository
public interface UserMapper {
User getUser (Long id) ;
}
4. 定义一个映射文件(userMapper.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="com.cq3jk.demomybatis.mapper.UserMapper">
<!--根据ID查询用户-->
<select id="getUser" parameterType="long" resultType="user">
select id, user_name as userName, sex, note
from t_user
where id = #{id}
</select>
</mapper>
- <mapper> 元素的 namespace 属性为需要映射的接口
- select中的id与映射的接口保持一致
- parameterType 属性配置为参数类型
- resu tType 指定返回值类型,此处为别名,也可以使用全限定名
- 列名与POJO的属性名保持一致,也可开启驼峰
二、Spring boot 整合Mybatis
1. 使用@MapperScan 定义扫描 - 最简单的方法
@SpringBootApplication(scanBasePackages = "com.cq3jk.demomybatis")
@MapperScan(
basePackages = "com.cq3jk.demomybatis.mapper", //指定扫描包
// 指定 SqlSessionFactory,如果sqlSessionTemplate被指定,则作废
// 这里有一个或多个的Spring的容器
sqlSessionFactoryRef = "sqlSessionFactory",
// 指定 sqlSessionTemplate,将忽略SqlSessionFactory配置
这里有一个或多个的Spring的容器
sqlSessionTemplateRef = "sqlSessionTemplate",
// 基于包下面扫描所有的接口类并注册,也有指定的属性
annotationClass = Repository.class
)
public class DemoMybatisApplication {
public static void main(String[] args) {
SpringApplication.run(DemoMybatisApplication.class, args);
}
}
2. 其他方式装配接口(了解)
- MapperFactoryBean类:针对一个接口配置
// SqlSessionFactory是 Spring Boot 自动为我们生成的,
@Autowired
SqlSessionFactory sqlSessionFactory ;
@Bean // 可以装备
public MapperFactoryBean<UserMapper> initUserMapper() {
MapperFactoryBean<UserMapper> bean = new MapperFactoryBean<UserMapper>();
bean.setMapperInterface(UserMapper.class);
bean.setSqlSessionFactory(sqlSessionFactory);
return bean;
}
- MapperScannerConfigurer类:扫描装配 MyBatis 的接口到Spring IoC 容器中
@Bean
public MapperScannerConfigurer mapperScannerConfig () {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
mapperScannerConfigurer.setBasePackage("com.cq3jk.demomybatis.mapper");
mapperScannerConfigurer.setAnnotationClass(Repository.class);
return mapperScannerConfigurer
}
3. resultMap 解析
association, collection 中有一个的属性resultMap来复用映射
<!--column不做限制,可以为任意表的字段,而property须为type 定义的pojo属性-->
<resultMap id="唯一的标识" type="映射的pojo对象">
<id column="表的主键字段,或者可以为查询语句中的别名字段" jdbcType="字段类型" property="映射pojo对象的主键属性" />
<result column="表的一个字段(可以为任意表的一个字段)" jdbcType="字段类型" property="映射到pojo对象的一个属性(须为type定义的pojo对象中的一个属性)"/>
<!-- 一对一映射到JavaBean的某个“复杂类型”属性 -->
<association property="pojo的一个对象属性" javaType="pojo关联的pojo对象">
<id column="关联pojo对象对应表的主键字段" jdbcType="字段类型" property="关联pojo对象的主席属性"/>
<result column="任意表的字段" jdbcType="字段类型" property="关联pojo对象的属性"/>
</association>
<!--
一对多映射到JavaBean中的某个集合,
集合中的property须为oftype定义的pojo对象的属性
-->
<collection property="pojo的集合属性" ofType="集合中的pojo对象">
<id column="集合中pojo对象对应的表的主键字段" jdbcType="字段类型" property="集合中pojo对象的主键属性" />
<result column="可以为任意表的字段" jdbcType="字段类型" property="集合中的pojo对象的属性" />
</collection>
</resultMap>
<!--
该模型由一个
作者编写的博客组成,
其中包含许多帖子,每个帖子可能没有或有许多评论和标记
-->
<resultMap id="detailedBlogResultMap" type="Blog">
<!-- 2. 注入到字段或 JavaBean 属性的普通结果-->
<result property="title" column="blog_title"/>
<!--
3. 一对一映射到JavaBean的某个“复杂类型”属性
4. association中有一个的属性resultMap来复用映射
-->
<association property="author" javaType="Author">
<!--设置该项可以有效地提升MyBatis的性能 -->
<id property="id" column="author_id"/>
<result property="username" column="author_username"/>
</association>
<!-- 4. 一对多映射到JavaBean中的某个集合 -->
<collection property="posts" ofType="Post">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<association property="author" javaType="Author"/>
<collection property="comments" ofType="Comment">
<id property="id" column="comment_id"/>
</collection>
<!--使用结果值来决定使用哪个 resultMap or resultType-->
<discriminator javaType="int" column="draft">
<case value="1" resultType="DraftPost"/>
</discriminator>
</collection>
</resultMap>
collection标签使用嵌套查询
// 注意:
// <collection>标签中的column:
// 要传递给select查询语句的参数,如果传递多个参数,格式为column= ” {参数名1=表字段1,参数名2=表字段2} ;
<collection column="传递给嵌套查询语句的字段参数"
property="pojo对象中集合属性"
ofType="集合属性中的pojo对象"
select="嵌套的查询语句" >
</collection>
// 示例如下
<select id="getById" resultMap="ShopResultMap">
select id, name, category_id
from t_shop
where id= #{id};
</select>
<resultMap id="ShopResultMap" type="shop">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="name" property="name" />
<result column="category_id" property="categoryId" />
<collection column="{sId=id}" property="attributes" ofType="attributes" select="getAttribute" >
</collection>
</resultMap>
<select id="getAttribute" resultMap="AttributeResultMap">
select id, sid, attr_name
from t_shop_attribute
where sid = #{sId};
</select>
<resultMap id="AttributeResultMap" type="attribute">
<id column="id" property="id" />
<result column="attr_name" property="attributeName" />
</resultMap>
4. 参数传递
#{} 与 ${} 的区别:
#{} 拿到值之后,拼装sql,会自动对值添加单引号”
${} 则把拿到的值直接拼装进sql,如果需要加单引号”,必须手动添加,一般用于动态传入表名或字段名使用,同时需要添加属性statementType=”STATEMENT”,使用非预编译模式
基本数据类型(int,String,Date等)
1、 只能传入一个参数,通过#{参数名}
public List<User> selectUserByOrgId(String orgId);
select * from user where org_id = #{orgId}
2、 传入多个参数,通过#{0}、#{1}……索引方式
public User selectUserByNameAndAge(String name,int age);
select * from user where name = #{0} and age = #{1}
3、传入多个参数,通过#{参数名}传多个值,可以使用@param()注解
public User selectUserByNameAndAge(@param("name")String name, @param("age")int age);
select * from user where name = #{name} and age = #{age}
复杂数据类型(包含JAVA实体类、Map)
4、传入多个基本类型参数,参数用map封装,通过#{mapKey}取值
public User selectUserByNameAndAge(Map map);
<select id="selectUserByNameAndAge" parameterType="Map" resultType="user">
select * from user where name = #{name} and age = #{age}
</select>
5、使用map封装实体类,通过通过#{mapKey.attributeName}取值
public User selectUserByNameAndAge(Map map);
select * from user where name = #{user.name} and age = #{user.age}
6、直接传入实体参数,通过#{属性名}取值
public User selectUserByNameAndAge(User userParam);
<select id="selectUserByNameAndAge" parameterType="User" resultType="user">
select * from user where name = #{userParam.name} and age = #{userParam.age}
</select>
mybatis中如果用了if那么传进来的参数不能直接单独传入,要封装到map或vo(对象)中
5. 返回自增长主键
- 第一种
// id会直接将映射到参数的实体上使用时直接使用参数的实体get获取值
<insert id="insertBatchReturnId" useGeneratedKeys="true" keyProperty="id" parameterType="xxx" >
- 第二种 (oracl需额外的配置)
<insert id="add" parameterType="EStudent">
// 下面是SQLServer获取最近一次插入记录的主键值的方式
<selectKey resultType="_long" keyProperty="id" order="AFTER">
select @@IDENTITY as id
</selectKey>
insert into TStudent(name, age) values(#{name}, #{age})
</insert>
6. 分页插件(pagehelper)
spring boot 集成mybatis实现分页功能的实例
https://blog.csdn.net/wufewu/article/details/84586489