MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架,其主要就完成2件事情:
-
- 封装JDBC操作
-
- 利用反射打通Java类与SQL语句之间的相互转换
MyBatis的主要设计目的就是让我们对执行SQL语句时对输入输出的数据管理更加方便,所以方便地写出SQL和方便地获取SQL的执行结果才是MyBatis的核心竞争力。
接口映射
在使用MyBatis的时候,都用的是Dao接口和XML文件里的SQL一一对应来进行使用的。那你是否思考过二者是如何建立关系的?
MyBatis会先解析这些XML文件,通过XML文件里面的命名空间(namespace)跟DAO建立关系;然后XML中的每段SQL会有一个id跟DAO中的接口进行关联。
Dao接口里的方法,是不能重载的,因为是全限名+方法名的保存和寻找策略
通常一个Xml映射文件,都会写一个Dao接口与之对应。Dao接口,就是人们常说的Mapper接口,接口的全限名,就是映射文件中的namespace的值,接口的方法名,就是映射文件中MappedStatement的id值,接口方法内的参数,就是传递给sql的参数。Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MappedStatement。
如果配置了namespace,那么id是可以重复的,因为我们的Statement实际上就是namespace+id
举例:com.mybatis3.mappers.StudentDao.findStudentById,可以唯一找到namespace为com.mybatis3.mappers.StudentDao下面id = findStudentById的MappedStatement。在Mybatis中,每一个<select>、<insert>、<update>、<delete>标签,都会被解析为一个MappedStatement对象。
#{}和${}的区别是什么?
- #{}解析传递进来的参数数据
- ${}对传递进来的参数原样拼接在SQL中
- Mybatis 在处理#{}时,会将 sql 中的#{}替换为?号,调用 PreparedStatement 的 set 方法来赋值;
Mybatis 在处理 美元符号{} 时,就是把${}替换成变量的值 - #{}是预编译处理,${}是字符串替换。
- 使用#{}可以有效的防止SQL注入,提高系统安全性。
select * from ${tableName} where name = #{name}
在这个例子中,如果表名为
user; delete user; –
则动态解析之后 sql 如下:
select * from user; delete user; – where name = ?;
--之后的语句被注释掉,而原本查询用户的语句变成了查询所有用户信息+删除用户表的语句,会对数据库造成重大损伤,极大可能导致服务器宕机。
'#‘相当于对数据 加上 双引号,’$'相当于直接显示数据
'#'将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。
'$'将传入的数据直接显示生成在sql中。
- #{} 用于CRUD语句
${} 则用于模糊查询(记得加%%哦),}一般用在order by, limit, group by等场所。
如何获取自动生成的(主)键值?
如果我们一般插入数据的话,如果我们想要知道刚刚插入的数据的主键是多少(一般这个主键是自增ID),一般情况下我们可能在以某个唯一字段与数据库进行一次查询交互,获取到自增id,但是这样相对比较麻烦,我们可以通过对mybatis进行配置。
<insert id="insert" parameterType="com.qufenqi.pay.settlement.dao.po.SettleBasicData" useGeneratedKeys="true"
keyProperty="id" keyColumn="id">
insert into sett_basic_data (id, biz_order_no, biz_type,
fund_type, trade_mode, merchant_id, merchant_name,
create_time, update_time)
values (#{id,jdbcType=BIGINT}, #{bizOrderNo,jdbcType=VARCHAR}, #{bizType,jdbcType=VARCHAR},
#{fundType,jdbcType=VARCHAR}, #{tradeMode,jdbcType=VARCHAR}, #{merchantId,jdbcType=VARCHAR}, #{merchantName,jdbcType=VARCHAR},
#{createTime,jdbcType=TIMESTAMP}, #{updateTime,jdbcType=TIMESTAMP})
</insert>
在上述方法中添加useGeneratedKeys="true" keyProperty="id" keyColumn="id"
settleBasicDataMapper.insert(settleBasicData); settleBasicData.getId();
代码亲测有效
在mapper中如何传递多个参数?
-
使用占位符的思想
其中,#{0}代表接收的是dao层中的第一个参数,#{1}代表dao层中第二参数,更多参数一致往后加即可。
-
采用Map传多参数 parameterType=“hashmap”
-
Dao层的函数方法,和占位符有些类似,目前单个参数用的主流方法(使用@Param注解)
-
通过注解的方法查询(配合@Param注解)
-
采用javaBean(一般应用于更新和查询情况)
这种方法很直观,但需要建一个实体类,扩展不容易,需要加属性,看情况使用。
附带一个批量更新数据库的sql
对SettleBasicData集合中的每条数据进行更新
int updateBatch(@Param(value = "list") List<SettleBasicData> list);
<update id="updateBatch" parameterType="java.util.List">
<foreach collection="list" item="item" index="index" open="" close="" separator=";">
update sett_basic_data
set
status = #{item.status,jdbcType=VARCHAR},
callback_status = #{item.callbackStatus,jdbcType=VARCHAR},
update_time = #{item.updateTime,jdbcType=TIMESTAMP}
where biz_order_no = #{item.bizOrderNo,jdbcType=VARCHAR}
and biz_type = #{item.bizType,jdbcType=VARCHAR}
and fund_type = #{item.fundType,jdbcType=VARCHAR}
</foreach>
</update>
在jdbc链接数据库时添加一下配置
?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
亲手采过的坑。
这事因为原来mysql的批量更新是要我们主动去设置的, 就是在数据库的连接url上设置一下,加上* &allowMultiQueries=true *即可。
字段映射
将表中的字段与我们建立的entity实体进行建立关联
通过resultMap来映射字段名和实体类属性名的一一对应的关系
<select id="getOrder" parameterType="int" resultMap="orderresultmap">
select * from orders where order_id=#{id}
</select>
//type对对应的实体类
<resultMap type=”me.gacl.domain.order” id=”orderresultmap”>
<!–用id属性来映射主键字段–>
<id property=”id” column=”order_id”/>
<!–用result属性来映射非主键字段,property为实体类属性名,column为数据表中的属性–>
<result property = “orderno” column =”order_no”/>
<result property=”price” column=”order_price” />
</reslutMap>