• java中的基本类型会有默认值,所以在实体类中不要使用基本类型

2.2 使用xml方式

  1. <mappers>
  2. <package name="com.ql.simple.mapper"/>
  3. </mappers>

该配置会找该包下的所有接口,循环对接口进行以下操作:

  1. 判断接口对应的命名空间是否已经存在,如果存在就抛出异常,不存在就继续操作
  2. 加载接口对于的xml文件,将接口全限定名转换为路径
  3. 处理接口中的注解方法

    2.3 select用法

    1. <resultMap id="userMap" type="com.ql.simple.model.SysUser">
    2. <id property="id" column="id"/>
    3. <result property="userName" column="user_name"/>
    4. <result property="userPassword" column="user_password"/>
    5. <result property="userInfo" column="user_info"/>
    6. <result property="headImg" column="head_img" jdbcType="BLOB"/>
    7. <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
    8. </resultMap>
    resultMap包含的所有属性如下:
  • id:必填
  • type:必填
  • extends:选填,配置当前的resultMap继承自其它的resultMap,属性值为继承resultMap的id
  • autoMapping:选填,可选值true或false,用于配置是否启用非映射字段的自动映射功能

resultMap包含的所有标签如下:

  • constructor:配置使用构造方法注入结果,包含以下两个子标签
    • idArg:id参数
    • arg:注入到构造方法的一个普通参数
  • id
  • result
  • association:一个复杂的类型关联,许多结果将包成这种类型
  • collection:复杂类型的集合
  • discrimination:根据结果值来决定使用哪个结果映射
  • case:基于某些值的结果映射

id和result标签包含的属性:

  • column
  • property
  • javaType:一个Java类的完全限定名,或一个类型别名
  • jdbcType:列对应的数据库类型
  • typeHandler:使用这个属性可以覆盖默认的类型处理器

  1. <select id="selectAll" resultType="com.ql.simple.model.SysUser">
  2. select id,
  3. user_name userName,
  4. user_password userPassword,
  5. user_email userEmail,
  6. user_info userInfo,
  7. head_img headImg,
  8. create_time createTime
  9. from sys_user
  10. </select>

需要在sql中为所有列和属性名不一致的列设置别名,通过设置别名使最终的查询结果列和resultType指定对象的属性名保持一致,进而实现自动映射


  1. <settings>
  2. <setting name="mapUnderscoreToCamelCase" value="true"/>
  3. </settings>

该配置可以自动将以下划线命名的数据库列映射到java对象的驼峰式命名属性中
使用该配置之后,前面的selectAll可以改写为:

  1. <select id="selectAll" resultType="com.ql.simple.model.SysUser">
  2. select id,
  3. user_name,
  4. user_password,
  5. user_email,
  6. user_info,
  7. head_img,
  8. create_time
  9. from sys_user
  10. </select>

  1. @Data
  2. public class SysRole {
  3. private Long id;
  4. private String roleName;
  5. private Integer enabled;
  6. private Long createBy;
  7. private Date createTime;
  8. private SysUser user;
  9. }

在SysRole类中添加SysUser字段,这样在联表查询的时候,不仅可以查询出SysRole的信息还可以查出SysUser的信息

  1. <select id="selectRolesByUserId" resultType="com.ql.simple.model.SysRole">
  2. select r.id,
  3. r.role_name roleName,
  4. r.enabled,
  5. r.create_by,
  6. r.create_time,
  7. u.user_name as "user.userName",
  8. u.user_email as "user.userEmail"
  9. from sys_user u
  10. inner join sys_user_role ur on u.id = ur.user_id
  11. inner join sys_role r on ur.role_id = r.id
  12. where u.id = #{userId}
  13. </select>

u.user_name as “user.userName”,前面的user_name是sys_user表中的属性,后面的user是SysRole中的属性user

2.4 insert用法

  1. <insert id="insert">
  2. insert into sys_user(id,
  3. user_name,
  4. user_password,
  5. user_email,
  6. user_info,
  7. head_img,
  8. create_time)
  9. values ( #{id}, #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP} )
  10. </insert>

为了防止类型错误,对于一些特殊的数据类型,建议指定具体的jdbcType
标签包含如下属性:

  • id
  • parameterType:即将传入的语句参数的完全限定类名或别名
  • flushCache:默认为true,任何时候只要语句被调用,都会清空一级缓存和二级缓存
  • timeout
  • statementType:STATEMENT、PREPARED、CALLABLE
  • useGeneratedKeys:默认为false,如果为true,会使用JDBC的getGeneratedKeys方法取出由数据库内部生成的主键
  • keyProperty:通过getGeneratedKeys获取主键值后将要赋值的属性名。如果希望得到多个数据库自动生成的列,属性值也可以是以逗号分隔的属性名称列表
  • keyColumn:仅对insert和update有用。通过生成的键值设置 中的列名, 这个设置仅在某些数据库(如 PostgreSQL )中是必须的, 当主键列不是中的第列时要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表
  • databaseId:如果配置了databaseIdProvider,会加载所有的不带databaseId的或匹配当前databaseId的语句。如果同时存在带databaseId和不带databaseId的语句,后者会被忽略

BLOB对应的类型是ByteArrayInputStream,二进制数据流 date、time、datetime对应的jdbc类型分别为DATE、TIME、TIMESTAMP

2.4.2 使用JDBC方式返回主键自增的值

  1. <insert id="insert2" useGeneratedKeys="true" keyProperty="id">
  2. insert into sys_user(id,
  3. user_name,
  4. user_password,
  5. user_email,
  6. user_info,
  7. head_img,
  8. create_time)
  9. values ( #{id}, #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP} )
  10. </insert>

useGeneratedKey设置为true之后,会使用JDBC的getGeneratedKeys方法取出由数据库内部生成的主键。获得主键值后将其赋值给keyProperty配置的id属性

2.4.3 使用selectKey返回主键的值

上面回写主键的方法只适用于支持主键自增的数据库
使用来获取,不仅适用于不提供主键自增功能的数据库,也适用于提供主键自增功能的数据库

  1. <insert id="insert3">
  2. insert into sys_user(id,
  3. user_name,
  4. user_password,
  5. user_email,
  6. user_info,
  7. head_img,
  8. create_time)
  9. values ( #{id}, #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP} )
  10. <selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
  11. select last_insert_id()
  12. </selectKey>
  13. </insert>

order值为after,因为当前记录的主键值在insert语句执行成功之后才能获取到。而在oracle中,该值要设置为before

2.5 update用法

  1. <update id="updateById">
  2. update sys_user
  3. set user_name=#{userName},
  4. user_password=#{userPassword},
  5. user_email=#{userEmail},
  6. user_info=#{userInfo},
  7. head_img=#{headImg,jdbcType=BLOB},
  8. create_time=#{createTime,jdbcType=TIMESTAMP}
  9. where id=#{id}
  10. </update>

2.6 delete用法

  1. /**
  2. * 通过主键删除
  3. * @param id
  4. * @return
  5. */
  6. int deleteById(Long id);
  7. /**
  8. * 通过主键删除
  9. * @param user
  10. * @return
  11. */
  12. int deleteById(SysUser user);
  1. <delete id="deleteById">
  2. delete from sys_user where id=#{id}
  3. </delete>

2.7 多个接口参数的用法

  1. /**
  2. * 根据用户id和角色的enabled状态获取用户的角色
  3. * @param userId
  4. * @param enabled
  5. * @return
  6. */
  7. List<SysRole> selectRolesByUserIdAndRoleEnabled(@Param("userId") Long userId, @Param("enabled") Integer enabled);
  1. <select id="selectRolesByUserIdAndRoleEnabled" resultType="com.ql.simple.model.SysRole">
  2. select r.id,
  3. r.role_name,
  4. r.enabled,
  5. r.create_by,
  6. r.create_time
  7. from sys_user u
  8. inner join sys_user_role ur on u.id = ur.user_id
  9. inner join sys_role r on ur.role_id = r.id
  10. where u.id = #{userId} and r.enabled = #{enabled}
  11. </select>

给参数配置@Param之后,就会自动将参数封装为Map类型,当只有一个参数(基本类型或用于TypeHandler配置的类型)可以不使用注解
在使用JavaBean的时候,用法略有不同:

  1. /**
  2. * 根据用户id和角色的enable状态获取用户的角色
  3. * @param user
  4. * @param role
  5. * @return
  6. */
  7. List<SysRole> selectRolesByUserAndRole(@Param("user") SysUser user, @Param("role") SysRole role);
  1. <select id="selectRolesByUserAndRole" resultType="com.ql.simple.model.SysRole">
  2. select r.id,
  3. r.role_name,
  4. r.enabled,
  5. r.create_by,
  6. r.create_time
  7. from sys_user u
  8. inner join sys_user_role ur on u.id = ur.user_id
  9. inner join sys_role r on ur.role_id = r.id
  10. where u.id = #{user.id} and r.enabled = #{role.enabled}
  11. </select>

这时要通过点取值方式使用

2.8 Mapper接口动态代理实现原理

Mapper接口没有实现类却能被正常调用的原因:

  1. public class MyMapperProxy<T> implements InvocationHandler {
  2. private Class<T> mapperInterface;
  3. private SqlSession sqlSession;
  4. public MyMapperProxy(Class<T> mapperInterface, SqlSession sqlSession) {
  5. this.mapperInterface = mapperInterface;
  6. this.sqlSession = sqlSession;
  7. }
  8. @Override
  9. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  10. // 不同的sql类型,要调用sqlSession不同的方法
  11. // 这里只考虑没有参数参数的情况
  12. List<T> list = sqlSession.selectList(mapperInterface.getCanonicalName() + "." + method.getName());
  13. // 返回值也有很多情况,这里不做处理
  14. return list;
  15. }
  16. }