Mybatis入门简版(补充)
一、Mybatis 中$与#的区别
#相当于对数据 加上 双引号,$相当于直接显示数据
1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by "111", 如果传入的值是id,则解析成的sql为order by "id".
2. $将传入的数据直接显示生成在sql中。如:order by $user_id$,如果传入的值是111,那么解析成sql时的值为order by user_id, 如果传入的值是id,则解析成的sql为order by id.
3. #方式能够很大程度防止sql注入。
4.$方式无法防止Sql注入。
5.$方式一般用于传入数据库对象,例如传入表名.
6.一般能用#的就别用$.
MyBatis排序时使用order by 动态参数时需要注意,用$而不是#
二、Mybatis映射文件里的<selectkey>
我们在数据库插入一条数据(主键是数据库生成)的时候,经常是需要返回插入这条数据的(数据库生成的)主键。
比如插入用户信息JavaBean时,id不需要我们设置(自增),那么插入后,我们想马上得这个JavaBean的ID。
可以下面这样改:
<insert id="saveUser" parameterType="cn.itcast.mybatis.pojo.User"> <selectKey keyColumn="id" keyProperty="id" order="AFTER" resultType="int"> SELECT LAST_INSERT_ID() </selectKey> INSERT INTO `user` (username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address}) </insert>
其中:selectKey 标签实现主键返回
keyColumn:
主键对应的表中的哪一列
keyProperty:
主键对应的pojo中的哪一个属性
order:
设置在执行insert语句前执行查询id的sql,还是在执行insert语句之后执行查询id的sql
MySQL填AFTER ,Oracle填BEFORE
resultType:
设置返回的id的类型
三、映射xml文件中的resultMap
1.介绍
resultType可以指定将查询结果映射为pojo,但需要pojo的属性名和sql查询的列名一致方可映射成功。
如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系 ,resultMap实质上还需要将查询结果映射到pojo对象中。
2.使用(由resultType改用resultMap)比如对于数据库里user_id这种字段,逆向工程会生成userId属性的pojo
其中:property:主键在pojo中的属性名,column:主键在数据库中的列名<!-- resultMap最终还是要将结果映射到pojo上,type就是指定映射到哪一个pojo --> <!-- id:设置ResultMap的id --> <resultMap type="cn.ssm.pojo.order" id="orderResultMap"> <result property="userId" column="user_id" />//只要写那个不一样的就行了! </resultMap> <!-- 查询所有的订单数据 --> <select id="queryOrderAll" resultMap="orderResultMap"> SELECT id, user_id, number, createtime, note FROM `order` </select>
四、动态SQL(基于OGNL表达式)
1.if标签
<!-- 根据条件查询用户 --> <select id="queryUserByWhere" parameterType="user" resultType="user"> SELECT id, username, birthday, sex, address FROM `user` WHERE 1=1 <if test="sex != null and sex != ''"> AND sex = #{sex} </if> <if test="username != null and username != ''"> AND username LIKE '%${username}%' </if> </select>
2.where标签
上面的例子里,还得写个1=1 防止出现 where and 这种错误情况。其实这种情况可以通过where标签解决
<!-- 根据条件查询用户 --> <select id="queryUserByWhere" parameterType="user" resultType="user"> SELECT id, username, birthday, sex, address FROM `user` <!-- where标签可以自动添加where,同时处理sql语句中第一个and关键字 --> <where> <if test="sex != null"> AND sex = #{sex} </if> <if test="username != null and username != ''"> AND username LIKE '%${username}%' </if> </where> </select>
3.SQL片段
五、多表查询Sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的。
4.foreach标签把上面例子中的id, username, birthday, sex, address提取出来,作为sql片段,如下:
<!-- 声明sql片段 --> <sql id="userFields"> id, username, birthday, sex, address </sql> <!-- 根据条件查询用户 --> <select id="queryUserByWhere" parameterType="user" resultType="user"> <!-- 使用include标签加载sql片段;refid是sql片段id --> SELECT <include refid="userFields" /> FROM `user` <where> <if test="sex != null"> AND sex = #{sex} </if> <if test="username != null and username != ''"> AND username LIKE '%${username}%' </if> </where> </select>
如果要使用别的Mapper.xml配置的sql片段,可以在refid里面加上对应的Mapper.xml的namespace
向sql传递数组或List,mybatis使用foreach解析,比如:
根据多个id查询用户信息
查询sql:
SELECT * FROM user WHERE id IN (1,10,24)<!-- 根据ids查询用户 --> <select id="queryUserByIds" parameterType="queryVo" resultType="user"> SELECT * FROM `user` <where> <!-- foreach标签,进行遍历 --> <!-- collection:遍历的集合,这里是QueryVo的ids属性 --> <!-- item:遍历的项目,可以随便写,,但是和后面的#{}里面要一致 --> <!-- open:在前面添加的sql片段 --> <!-- close:在结尾处添加的sql片段 --> <!-- separator:指定遍历的元素之间使用的分隔符 --> <foreach collection="ids" item="item" open="id IN (" close=")" separator=","> #{item} </foreach> </where> </select>
多表查询的时候通常会要返回多个表的数据,即多个pojo的部分数据。
5.1一对一查询(两张表)
此时要么采取新建pojo(继承一个pojo再加上新需要的)去包裹查出来的数据,要么在原pojo里组合另外一个pojo(作为成员对象),即继承和组合 两种方法。
5.1.1采用继承的方法(正常采用resultType即可)
5.1.2采用组合的方式
那么此时多个pojo会有相同属性,如何映射?采取resultMap
pojo可能会要改成下面这样:
那么此时查询结果对pojo的映射得改改了
<resultMap type="order" id="orderUserResultMap"> <id property="id" column="id" /> <result property="userId" column="user_id" /> <result property="number" column="number" /> <result property="createtime" column="createtime" /> <result property="note" column="note" /> <!-- association :配置一对一属性 --> <!-- property:order里面的User属性名 --> <!-- javaType:属性类型 --> <association property="user" javaType="user"> <!-- id:声明主键,表示user_id是关联查询对象的唯一标识--> <id property="id" column="user_id" /> <result property="username" column="username" /> <result property="address" column="address" /> </association> </resultMap> <!-- 一对一关联,查询订单,订单内部包含用户属性 --> <select id="queryOrderUserResultMap" resultMap="orderUserResultMap"> SELECT o.id,o.user_id,o.number,o.createtime,o.note,u.username,u.address FROM `order` o LEFT JOIN `user` u ON o.user_id = u.id </select>
5.2一对多查询
如下:
那么映射文件如下:
<resultMap type="user" id="userOrderResultMap"> <!-- 配置主键,将主键相同的记录映射到一个集合里去--> <id property="id" column="id" /> <result property="username" column="username" /> <result property="birthday" column="birthday" /> <result property="sex" column="sex" /> <result property="address" column="address" /> <!-- 配置一对多的关系 --> <collection property="orders" javaType="list" ofType="order"> <!-- 配置主键,是关联Order的唯一标识 --> <id property="id" column="oid" /> <result property="number" column="number" /> <result property="createtime" column="createtime" /> <result property="note" column="note" /> </collection> </resultMap> <!-- 一对多关联,查询订单同时查询该用户下的订单 --> <select id="queryUserOrder" resultMap="userOrderResultMap"> SELECT u.id,u.username,u.birthday,u.sex,u.address,o.id oid,o.number,o.createtime,o.note FROM `user` u LEFT JOIN `order` o ON u.id = o.user_id </select>