主要内容
mybatis映射器
映射器是mybatis中的核心组件,所有数据库的操作都在映射器中被定义,也就是说,我们对数据库的crud操作,都是由映射器实现。
映射器工作原理
前面我们已经使用过映射器,一个比较简单的映射器配置如下:
1 2 3 4 5 6 7 8 9 10 11 |
<?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="cn.sharpcode.mapper.UserMapper"> <select id="selectUser" parameterType="int" resultType="cn.sharpcode.po.User"> SELECT * FROM user WHERE id = #{id} </select> </mapper> |
实际上,映射器文件中定义了一个类,类名就是UserMapper
,且<select>元素本身就是完整的方法签名:它包括方法名称(id),参数类型(parameterType)和返回类型(resultType)。因此,mapper中的这些元素可以理解为用于方法定义。
除了<select>元素外,mapper文件中可使用的元素还有<insert>
、<update>
和<delete>
。<select>元素是唯一一个需要强制使用resultType的元素,parameterType对所有元素都是可选的。
下面是简单的<update>元素使用例子:
1 2 3 4 5 6 7 8 9 10 11 |
<?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="cn.sharpcode.mapper.UserMapper"> <update id="updateSex"> UPDATE user SET sex = #{sex} WHERE id = #{id} </update> </mapper> |
UserMapper接口定义:
1 2 3 4 5 6 |
public interface UserMapper { User selectUser(Integer id); int updateSex(Integer id); } |
测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
@Test public void testUpdate() throws IOException { String resource = "mybatis-config.xml"; InputStream resourceAsStream = Resources.getResourceAsStream(resource); SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream); SqlSession sqlSession = build.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.selectUser(1); user.setSex(Sex.FEMALE); int i = mapper.updateSex(user.getId()); System.out.println(i); sqlSession.close(); } |
自动映射
虽然没有严格定义,但是mybatis中的映射可以分为参数映射和结果映射两种。
参数自动映射
上面<update>元素中定义的sql语句要求传入两个参数,一个是#{sex}
,另一个是#{id}
;但是你会发现updateSex方法只传递一个id参数就可以工作,这就是mybatis中自动映射带来的方便。自动映射就是当javaBean的属性和mapper中的sql参数占位符
具有相同名称的情况下,mybatis就会自动匹配并填入数据,注意是和占位符相同,而不是和sql中的列名相同。
传递多个参数
利用上面的这种便利,就可以轻松把多个参数传递到mapper中。除了利用JavaBean的属性映射外,还可以通过其他两种方式传递多个参数:使用map传递参数和使用注解传递参数。
使用Map传递参数
继续利用上面的<update>元素为例子,传入的参数分别是#{sex}和#{id}。这次利用Map<K,V>接口把这两个参数封装起来。
1 2 3 4 5 6 7 |
UserMapper mapper = sqlSession.getMapper(UserMapper.class); Map<String, Integer> map = new HashMap<>(); map.put("sex", 1); map.put("id", 2); int i = mapper.updateSex(map); |
测试代码之前需要把updateSex的参数类型更改为Map类型。
这种方法的缺点也显然易见的:传入的参数类型必须相同,例如这里全部都是Integer(枚举类型可以使用整型储存),如果参数类型不相同,是不可以使用这种方法的,所以,相比起javaBean属性映射,使用Map的灵活性较差。
使用注解传递参数
注解传递参数主要解决的问题是防止多个参数传递的时候参数混乱,达到参数匹配的目的。
使用@Param匹配参数。
mapper接口方法定义:
1 |
int updateSex(@Param("sex") Sex sex, @Param("id") Integer id); |
@Param(“sex”)表示第一个参数匹配sql占位符的#{sex},@Param(“id”)则匹配#{id}
测试代码:
1 2 3 |
UserMapper mapper = sqlSession.getMapper(UserMapper.class); int i = mapper.updateSex(Sex.FEMALE, 2); |
这种方法使用效率并不高,只需要了解。
结果自动映射
结果自动映射是指返回的数据自动填充到JavaBean的属性中,前提是数据库中的字段名称必须和JavaBean的属性相同。
使用resultMap解决字段匹配问题
虽然数据库字段和JavaBean属性相同的情况下数据可以自动映射,但是,很多时候两者的名称很可能不相同。这个时候可以使用resultMap解决字段匹配问题。
例如javaBean中的属性是username, 而数据库中的名称则是user_name,自动映射就无法进行。
resultMap的作用是明确指定JavaBean的属性和数据库字段的关系。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?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="cn.sharpcode.mapper.UserMapper"> <resultMap id="nameMap" type="cn.sharpcode.po.User"> <result property="username" column="user_name" /> </resultMap> <select id="selectUser" parameterType="int" resultType="cn.sharpcode.po.User" resultMap="nameMap"> SELECT * FROM user WHERE id = #{id} </select> </mapper> |
主键问题
主键问题主要发生在<insert>元素中,由于不同的程序设置主键的方式不同,那么根据实际情况对数据库进行主键操作是十分必要的。例如当主键是一个自增字段,那么,插入数据的时候我们就不需要为JavaBean的id设置值。
1 2 3 4 |
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id"> INSERT INTO user (id, user_name, password, regtime, sex) VALUES (#{id}, #{username}, #{password}, #{regtime}, #{sex}); </insert> |
useGeneratedKyes=”true”表示使用数据库内置主键支持,keyProperty=”id”说明主键名称是id。
使用自定义主键
有时候我们需要根据不同的规则创建主键的值,例如如果主键不存在,则第一次创建的时候主键值为1,否则每次主键值加2。
1 2 3 4 5 6 7 |
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id"> <selectKey keyProperty="id" resultType="int" order="BEFORE"> SELECT if(max(id) is NULL ,1,max(id)+2) as newId from user; </selectKey> INSERT INTO user (id, username, password, regtime, sex) VALUES (#{id}, #{username}, #{password}, #{regtime}, #{sex}); </insert> |
使用<selectKey>元素可以达到这个目的,selectKey里面执行的是合法的sql语句。
mapper中占位符#和$的区别
mybatis中sql语句使用的是预处理语句,使用#号的时候,如果传入的参数是字符串,那么mybatis会统一使用引号括起来,也就是传入的参数会作为一个合法的值替换掉预处理语句中的?号。
而使用$号,即使传入的参数是一个字符串,它也不会使用引号括起来,那么数据库执行的时候就会把该参数误解为一个column的名称。
举个例子:
1 2 3 4 5 |
<update id="updateSex"> UPDATE user SET sex = ${sex} WHERE id = #{id} </update> |
测试代码:
1 2 3 |
UserMapper mapper = sqlSession.getMapper(UserMapper.class); int i = mapper.updateSex(Sex.FEMALE, 1); |
当执行查询的时候,程序就会抛出异常:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column ‘FEMALE’ in ‘field list’
转载请注明:Pure nonsense » mybatis映射器(mapper)详解