- 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 createTime
from 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_time
from sys_user
</select>
@Data
public 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 u
inner join sys_user_role ur on u.id = ur.user_id
inner join sys_role r on ur.role_id = r.id
where 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_user
set 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_time
from sys_user u
inner join sys_user_role ur on u.id = ur.user_id
inner join sys_role r on ur.role_id = r.id
where 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_time
from sys_user u
inner join sys_user_role ur on u.id = ur.user_id
inner join sys_role r on ur.role_id = r.id
where 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;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 不同的sql类型,要调用sqlSession不同的方法
// 这里只考虑没有参数参数的情况
List<T> list = sqlSession.selectList(mapperInterface.getCanonicalName() + "." + method.getName());
// 返回值也有很多情况,这里不做处理
return list;
}
}