1.基于xml配置的映射器的概率
- cache - 给定命名空间的缓存配置
- cache-ref - 其他命名空间缓存配置的引用
- resultMap - 是最复杂也是最强大的元素,用来描述如何从数据库结果集中加载对象
- sql - 可被其他语句引用的可重用语句块
- insert - 映射插入语句
- update
- delete
- select
mapper配置最核心的两个要素是:SQL语句和映射规则。
1)sql insert update delete select是写SQL语句
2)resultMap是写映射规则的
2.select元素
2.1 自动映射和手动映射
- resultType和resultMap只用其中一个
参考TUserMapper.xml
<select id="selectByPrimaryKey" resultMap="BaseResultMap"
parameterType="java.lang.Integer">
select
<include refid="Base_Column_List" />
from t_user
where id = #{id,jdbcType=INTEGER}
</select>
其中BaseResultMap为手动进行映射:
<resultMap id="BaseResultMap" type="TUser">
<id column="id" property="id" jdbcType="INTEGER" />
<result column="user_name" property="userName" jdbcType="VARCHAR" />
<result column="real_name" property="realName" jdbcType="VARCHAR" />
<result column="sex" property="sex" jdbcType="TINYINT" />
<result column="mobile" property="mobile" jdbcType="VARCHAR" />
<result column="email" property="email" jdbcType="VARCHAR" />
<result column="note" property="note" jdbcType="VARCHAR" />
<result column="position_id" property="positionId" jdbcType="INTEGER" />
</resultMap>
自动映射
前提:SQL列名和JavaBean的属性是一致的
自动映射等级autoMappingBehavior设置为PARTIAL,谨慎使用FULL
使用resultType
如果列名和JavaBean不一致,mapUnderscoreToCamelCase设置为true。(规范命名时使用)-
相关的阿里规范说明——使用手动映射
2.2 传递多个查询入参
- 使用map传递参数:可读性差,导致可维护性和可扩展性差,杜绝使用
- 使用注解传递参数:直观明了,当参数小于5个时,建议使用
- 使用Java Bean的方式传递参数:当参数大于5个时,建议使用
List<TUser> selectByEmailAndSex1(Map<String, Object> param);
List<TUser> selectByEmailAndSex2(@Param("email")String email, @Param("sex")Byte sex);
List<TUser> selectByEmailAndSex3(EmailSexBean esb);
<select id="selectByEmailAndSex1" resultMap="BaseResultMap"
parameterType="map">
select
<include refid="Base_Column_List" />
from t_user a
where a.email like CONCAT('%', #{email}, '%') and
a.sex = #{sex}
</select>
<select id="selectByEmailAndSex2" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from t_user a
where a.email like CONCAT('%', #{email}, '%') and
a.sex = #{sex}
</select>
<select id="selectByEmailAndSex3" resultMap="BaseResultMap"
parameterType="com.enjoylearning.mybatis.entity.EmailSexBean">
select
<include refid="Base_Column_List" />
from t_user a
where a.email like CONCAT('%', #{email}, '%') and
a.sex = #{sex}
</select>
// 多参数查询
@Test
public void testManyParamQuery() {
// 2.获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取对应mapper
TUserMapper mapper = sqlSession.getMapper(TUserMapper.class);
String email = "qq.com";
Byte sex = 1;
// 第一种方式使用map
Map<String, Object> params = new HashMap<String, Object>();
params.put("email", email);
params.put("sex", sex);
List<TUser> list1 = mapper.selectByEmailAndSex1(params);
System.out.println(list1.size());
// 第二种方式直接使用参数
List<TUser> list2 = mapper.selectByEmailAndSex2(email, sex);
System.out.println(list2.size());
// 第三种方式用对象
EmailSexBean esb = new EmailSexBean();
esb.setEmail(email);
esb.setSex(sex);
List<TUser> list3 = mapper.selectByEmailAndSex3(esb);
System.out.println(list3.size());
}
3.resultMap元素
- 互联网应用中,大多数是用单表查询。因为数据量巨大,实现时是分库分表分布式的。
resultMap是Mybatis中最重要最强大的元素,让你从90%的JDBC ResultSets数据提取代码中解放出来。
设计思想是:简单的语句不需要明确的结果映射,复杂的语句只需要描述它们的关系即可。
<resultMap id="BaseResultMap" type="TUser">
<!-- <constructor>
<idArg column="id" javaType="int"/>
<arg column="user_name" javaType="String"/>
</constructor> -->
<id column="id" property="id" jdbcType="INTEGER" />
<result column="user_name" property="userName" jdbcType="VARCHAR" />
<result column="real_name" property="realName" jdbcType="VARCHAR" />
<result column="sex" property="sex" jdbcType="TINYINT" />
<result column="mobile" property="mobile" jdbcType="VARCHAR" />
<result column="email" property="email" jdbcType="VARCHAR" />
<result column="note" property="note" jdbcType="VARCHAR" />
<result column="position_id" property="positionId" jdbcType="INTEGER" />
</resultMap>
3.1 属性
3.2 子元素
3.2.1 id & result
-
id和result都将一个列的值映射到一个简单数据类型的属性或字段;
区别是,id表示的结果将是对象的标识属性(key主键一样),在比较对象实例时用到。可以提高整体的性能,尤其是缓存和嵌套结果映射(也就是联合映射)的时候。
3.2.2 constructor
- 一个pojo不存在没有参数的构造方法,就需要使用construtor
为了通过名称来引用构造方法参数,可以添加@Param注解,指定参数名称的前提下,以任意顺序编写arg元素。
<constructor>
<idArg column="id" javaType="int"/>
<arg column="user_name" javaType="String"/>
</constructor>
4.insert、update和delete元素
int insert1(TUser record);
<insert id="insert1" parameterType="TUser" useGeneratedKeys="true" keyProperty="id">
insert into t_user (id, user_name, real_name,
sex, mobile,
email,
note, position_id)
values (#{id,jdbcType=INTEGER},
#{userName,jdbcType=VARCHAR},
#{realName,jdbcType=VARCHAR},
#{sex,jdbcType=TINYINT}, #{mobile,jdbcType=VARCHAR},
#{email,jdbcType=VARCHAR},
#{note,jdbcType=VARCHAR},
#{positionId,jdbcType=INTEGER})
</insert>`
测试代码:
@Test
// 测试插入数据自动生成id
public void testInsertGenerateId1() throws IOException {
// 2.获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取对应mapper
TUserMapper mapper = sqlSession.getMapper(TUserMapper.class);
// 4.执行查询语句并返回结果
TUser user1 = new TUser();
user1.setUserName("test1");
user1.setRealName("realname1");
user1.setEmail("myemail1");
mapper.insert1(user1);
sqlSession.commit();
System.out.println(user1.getId());
}
4.1 selectKey元素——无自动增长时使用
对于id,Mysql是在插入之后拿到主键id,Oracle是在插入之前拿到主键id。
int insert2(TUser record);
<insert id="insert2" parameterType="TUser">
<selectKey keyProperty="id" order="AFTER" resultType="int">
select LAST_INSERT_ID()
</selectKey>
insert into t_user (id, user_name, real_name,
sex, mobile,
email,
note, position_id)
values (#{id,jdbcType=INTEGER},
#{userName,jdbcType=VARCHAR},
#{realName,jdbcType=VARCHAR},
#{sex,jdbcType=TINYINT}, #{mobile,jdbcType=VARCHAR},
#{email,jdbcType=VARCHAR},
#{note,jdbcType=VARCHAR},
#{positionId,jdbcType=INTEGER})
</insert>
测试代码:
@Test
// 测试插入数据自动生成id
public void testInsertGenerateId2() throws IOException {
// 2.获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取对应mapper
TUserMapper mapper = sqlSession.getMapper(TUserMapper.class);
// 4.执行查询语句并返回结果
TUser user2 = new TUser();
user2.setUserName("test2");
user2.setRealName("realname2");
user2.setEmail("myemai2l");
mapper.insert2(user2);
sqlSession.commit();
System.out.println(user2.getId());
}
5.sql元素
<sql id="Base_Column_List">
id, user_name, real_name, sex, mobile, email, note,
position_id
</sql>
<select id="selectByPrimaryKey" resultMap="BaseResultMap"
parameterType="java.lang.Integer">
select
<include refid="Base_Column_List" />
from t_user
where id = #{id,jdbcType=INTEGER}
</select>
6.参数:向sql语句中传递的可变参数
传值${}:传入的数据直接显式生成在sql中,无法防止sql注入
直接插入到sql语句中。预编译#{}:将传入的数据当成一个字符串,会对自动传入的数据加一个单引号,能够很大程序防止sql注入
使用占位符?表示。表名、选取的列是动态的,order by和in操作,可以考虑使用$
<select id="selectBySymbol" resultMap="BaseResultMap">
select
${inCol}
from ${tableName} a
where a.sex = #{sex}
order by ${orderStr}
</select>
测试程序:
@Test
// 参数#和参数$区别测试(动态sql 入门)
public void testSymbol() {
// 2.获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取对应mapper
TUserMapper mapper = sqlSession.getMapper(TUserMapper.class);
String inCol = "id, user_name, real_name, sex, mobile, email, note";
String tableName = "t_user";
Byte sex = 1;
String orderStr = "sex,user_name";
List<TUser> list = mapper.selectBySymbol(tableName, inCol, orderStr, sex);
System.out.println(list.size());
}
测试结果:
2018-09-24 15:03:30.859 [main] DEBUG c.e.mybatis.mapper.TUserMapper.selectBySymbol - ==> Preparing: select id, user_name, real_name, sex, mobile, email, note from t_user a where a.sex = ? order by sex,user_name
2018-09-24 15:03:30.920 [main] DEBUG c.e.mybatis.mapper.TUserMapper.selectBySymbol - ==> Parameters: 1(Byte)
2018-09-24 15:03:30.940 [main] DEBUG c.e.mybatis.mapper.TUserMapper.selectBySymbol - <== Total: 3
7.注解方式配置
注解方式就是将SQL语句直接写在接口上,对于需求比较简单的系统,效率较高。缺点在于,每次修改sql语句都要编译代码,对于复杂的sql语句可编辑性和可读性都差,一般不建议使用这种配置方式。
- @Select
@Results
@ResultMap
@Insert
@Update
@Delete
public interface TJobHistoryAnnoMapper {
int deleteByPrimaryKey(Integer id);
int insertSelective(TJobHistory record);
TJobHistory selectByPrimaryKey(Integer id);
int updateByPrimaryKeySelective(TJobHistory record);
int updateByPrimaryKey(TJobHistory record);
@Results(id="jobInfo",value={
@Result(property="id",column="id",id = true),
@Result(property="userId",column="user_id"),
@Result(property="compName",column="comp_name"),
@Result(property="years",column="years"),
@Result(property="title",column="title")
})
@Select("select id, user_id, comp_name, years, title from t_job_history"
+ " where user_id = #{userId}")
List<TJobHistory> selectByUserId(int userId);
@ResultMap("jobInfo")
@Select("select id, user_id, comp_name, years, title from t_job_history")
List<TJobHistory> selectAll();
@Insert("insert into t_job_history (id, user_id, comp_name, years, title)"
+ " values (#{id,jdbcType=INTEGER}, #{userId,jdbcType=INTEGER},"
+ "#{compName,jdbcType=VARCHAR},"
+ "#{years,jdbcType=INTEGER}, #{title,jdbcType=VARCHAR})")
@Options(useGeneratedKeys=true,keyProperty="id")
int insert(TJobHistory record);
}
测试代码
@Test
// 注解测试
public void testAnno() {
// 2.获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取对应mapper
TJobHistoryAnnoMapper mapper = sqlSession.getMapper(TJobHistoryAnnoMapper.class);
List<TJobHistory> list = mapper.selectByUserId(1);
System.out.println(list.size());
List<TJobHistory> listAll = mapper.selectAll();
System.out.println(listAll.size());
TJobHistory job = new TJobHistory();
job.setTitle("产品经理");
job.setUserId(1);
job.setCompName("美团");
job.setYears(3);
mapper.insert(job);
System.out.println(job.getId());
}
mapper配置:
<!-- 映射文件,mapper的配置文件 -->
<mappers>
<mapper resource="sqlmapper/TUserMapper.xml" />
<mapper class="com.enjoylearning.mybatis.mapper.TJobHistoryAnnoMapper"/>
</mappers>
结果:
018-09-24 15:22:50.596 [main] DEBUG c.e.m.mapper.TJobHistoryAnnoMapper.selectByUserId - ==> Preparing: select id, user_id, comp_name, years, title from t_job_history where user_id = ?
2018-09-24 15:22:50.636 [main] DEBUG c.e.m.mapper.TJobHistoryAnnoMapper.selectByUserId - ==> Parameters: 1(Integer)
2018-09-24 15:22:50.686 [main] DEBUG c.e.m.mapper.TJobHistoryAnnoMapper.selectByUserId - <== Total: 1
1
2018-09-24 15:22:50.690 [main] DEBUG c.e.mybatis.mapper.TJobHistoryAnnoMapper.selectAll - ==> Preparing: select id, user_id, comp_name, years, title from t_job_history
2018-09-24 15:22:50.693 [main] DEBUG c.e.mybatis.mapper.TJobHistoryAnnoMapper.selectAll - ==> Parameters:
2018-09-24 15:22:50.696 [main] DEBUG c.e.mybatis.mapper.TJobHistoryAnnoMapper.selectAll - <== Total: 6
6
2018-09-24 15:22:50.697 [main] DEBUG c.e.mybatis.mapper.TJobHistoryAnnoMapper.insert - ==> Preparing: insert into t_job_history (id, user_id, comp_name, years, title) values (?, ?,?,?, ?)
2018-09-24 15:22:50.698 [main] DEBUG c.e.mybatis.mapper.TJobHistoryAnnoMapper.insert - ==> Parameters: null, 1(Integer), 美团(String), 3(Integer), 产品经理(String)
2018-09-24 15:22:50.699 [main] DEBUG c.e.mybatis.mapper.TJobHistoryAnnoMapper.insert - <== Updates: 1
7
参考
- 1)享学课堂Lison老师笔记
- 2)阿里巴巴java开发手册 1.4.0