- java中的基本类型会有默认值,所以在实体类中不要使用基本类型
2.2 使用xml方式
<mappers><package name="com.ql.simple.mapper"/></mappers>
该配置会找该包下的所有接口,循环对接口进行以下操作:
- 判断接口对应的命名空间是否已经存在,如果存在就抛出异常,不存在就继续操作
- 加载接口对于的xml文件,将接口全限定名转换为路径
- 处理接口中的注解方法
2.3 select用法
resultMap包含的所有属性如下:<resultMap id="userMap" type="com.ql.simple.model.SysUser"><id property="id" column="id"/><result property="userName" column="user_name"/><result property="userPassword" column="user_password"/><result property="userInfo" column="user_info"/><result property="headImg" column="head_img" jdbcType="BLOB"/><result property="createTime" column="create_time" jdbcType="TIMESTAMP"/></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:使用这个属性可以覆盖默认的类型处理器
<select id="selectAll" resultType="com.ql.simple.model.SysUser">select id,user_name userName,user_password userPassword,user_email userEmail,user_info userInfo,head_img headImg,create_time createTimefrom sys_user</select>
需要在sql中为所有列和属性名不一致的列设置别名,通过设置别名使最终的查询结果列和resultType指定对象的属性名保持一致,进而实现自动映射
<settings><setting name="mapUnderscoreToCamelCase" value="true"/></settings>
该配置可以自动将以下划线命名的数据库列映射到java对象的驼峰式命名属性中
使用该配置之后,前面的selectAll可以改写为:
<select id="selectAll" resultType="com.ql.simple.model.SysUser">select id,user_name,user_password,user_email,user_info,head_img,create_timefrom sys_user</select>
@Datapublic class SysRole {private Long id;private String roleName;private Integer enabled;private Long createBy;private Date createTime;private SysUser user;}
在SysRole类中添加SysUser字段,这样在联表查询的时候,不仅可以查询出SysRole的信息还可以查出SysUser的信息
<select id="selectRolesByUserId" resultType="com.ql.simple.model.SysRole">select r.id,r.role_name roleName,r.enabled,r.create_by,r.create_time,u.user_name as "user.userName",u.user_email as "user.userEmail"from sys_user uinner join sys_user_role ur on u.id = ur.user_idinner join sys_role r on ur.role_id = r.idwhere u.id = #{userId}</select>
u.user_name as “user.userName”,前面的user_name是sys_user表中的属性,后面的user是SysRole中的属性user
2.4 insert用法
<insert id="insert">insert into sys_user(id,user_name,user_password,user_email,user_info,head_img,create_time)values ( #{id}, #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP} )</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方式返回主键自增的值
<insert id="insert2" useGeneratedKeys="true" keyProperty="id">insert into sys_user(id,user_name,user_password,user_email,user_info,head_img,create_time)values ( #{id}, #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP} )</insert>
useGeneratedKey设置为true之后,会使用JDBC的getGeneratedKeys方法取出由数据库内部生成的主键。获得主键值后将其赋值给keyProperty配置的id属性
2.4.3 使用selectKey返回主键的值
上面回写主键的方法只适用于支持主键自增的数据库
使用
<insert id="insert3">insert into sys_user(id,user_name,user_password,user_email,user_info,head_img,create_time)values ( #{id}, #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP} )<selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">select last_insert_id()</selectKey></insert>
order值为after,因为当前记录的主键值在insert语句执行成功之后才能获取到。而在oracle中,该值要设置为before
2.5 update用法
<update id="updateById">update sys_userset user_name=#{userName},user_password=#{userPassword},user_email=#{userEmail},user_info=#{userInfo},head_img=#{headImg,jdbcType=BLOB},create_time=#{createTime,jdbcType=TIMESTAMP}where id=#{id}</update>
2.6 delete用法
/*** 通过主键删除* @param id* @return*/int deleteById(Long id);/*** 通过主键删除* @param user* @return*/int deleteById(SysUser user);
<delete id="deleteById">delete from sys_user where id=#{id}</delete>
2.7 多个接口参数的用法
/*** 根据用户id和角色的enabled状态获取用户的角色* @param userId* @param enabled* @return*/List<SysRole> selectRolesByUserIdAndRoleEnabled(@Param("userId") Long userId, @Param("enabled") Integer enabled);
<select id="selectRolesByUserIdAndRoleEnabled" resultType="com.ql.simple.model.SysRole">select r.id,r.role_name,r.enabled,r.create_by,r.create_timefrom sys_user uinner join sys_user_role ur on u.id = ur.user_idinner join sys_role r on ur.role_id = r.idwhere u.id = #{userId} and r.enabled = #{enabled}</select>
给参数配置@Param之后,就会自动将参数封装为Map类型,当只有一个参数(基本类型或用于TypeHandler配置的类型)可以不使用注解
在使用JavaBean的时候,用法略有不同:
/*** 根据用户id和角色的enable状态获取用户的角色* @param user* @param role* @return*/List<SysRole> selectRolesByUserAndRole(@Param("user") SysUser user, @Param("role") SysRole role);
<select id="selectRolesByUserAndRole" resultType="com.ql.simple.model.SysRole">select r.id,r.role_name,r.enabled,r.create_by,r.create_timefrom sys_user uinner join sys_user_role ur on u.id = ur.user_idinner join sys_role r on ur.role_id = r.idwhere u.id = #{user.id} and r.enabled = #{role.enabled}</select>
2.8 Mapper接口动态代理实现原理
Mapper接口没有实现类却能被正常调用的原因:
public class MyMapperProxy<T> implements InvocationHandler {private Class<T> mapperInterface;private SqlSession sqlSession;public MyMapperProxy(Class<T> mapperInterface, SqlSession sqlSession) {this.mapperInterface = mapperInterface;this.sqlSession = sqlSession;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 不同的sql类型,要调用sqlSession不同的方法// 这里只考虑没有参数参数的情况List<T> list = sqlSession.selectList(mapperInterface.getCanonicalName() + "." + method.getName());// 返回值也有很多情况,这里不做处理return list;}}
