#{}和${}的区别是什么 #{}是预编译处理,对应的变量自动加上单引号 ‘’ ${}是字符串替换,对应的变量不会加上单引号 ‘’
Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值; Mybatis在处理${}时,就是把${}替换成变量的值。
使用#{}可以有效的防止SQL注入,提高系统安全性。 预编译语句的优势在于归纳 为:一次编译、多次运行,省去了解析优化等过程;此外预编译语句能防止sql注入。
什么是MyBatis的接口绑定?有哪些实现方式? 接口绑定,就是在MyBatis中任意定义接口,然后把接口里面的方法和SQL语句绑定,我们直接调用接口方法就可以, 这样比起原来了SqlSession提供的方法我们可以有更加灵活的选择和设置。
接口绑定有两种实现方式: 1 通过注解绑定,就是在接口的方法上面加上 @Select、@Update等注解,里面包含Sql语句来绑定;
2 通过xml里面写SQL来绑定, 在这种情况下,要指定xml映射文件里面的namespace必须为接口的全路径名。
当Sql语句比较简单时候,用注解绑定, 当SQL语句比较复杂时候,用xml绑定,一般用xml绑定的比较多。
Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式? 第一种是使用****标签,逐一定义列名和对象属性名之间的映射关系。
第二种是使用sql列的别名 功能,将列别名书写为对象属性名,比如T_NAME AS NAME,对象属性名一般是name,小写,但是列名不区分大小写,Mybatis会忽略列名大小写,智能找到与之对应对象属性名,你甚至可以写成T_NAME AS NaMe,Mybatis一样可以正常工作。
有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
Mybatis一对一、一对多的查询 比如班级学生老师 一个Class类中有Teacher属性和List属性 如下例子
MyBatis 中使用collection标签 来解决一对多的关联查询,collection标签可用的属性如下: property:指的是集合属性的值. ofType:指的是集合中元素的类型. column:所对应的外键字段名称. select:使用另一个查询封装的结果.
MyBatis 中使用association标签 来解决一对一的关联查询,association标签可用的属性如下: property:对象属性的名称. javaType:对象属性的类型. column:所对应的外键字段名称. select:使用另一个查询封装的结果!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <mapper namespace ="com.lcb.mapping.userMapper" > <select id ="getClass2" parameterType ="int" resultMap ="ClassesResultMap2" > select * from class c,teacher t,student s where c.teacher_id=t.t_id and c.c_id=s.class_id and c.c_id=#{id} </select > <resultMap type ="com.lcb.user.Classes" id ="ClassesResultMap2" > <id property ="id" column ="c_id" /> <result property ="name" column ="c_name" /> <association property ="teacher" javaType ="com.lcb.user.Teacher" > <id property ="id" column ="t_id" /> <result property ="name" column ="t_name" /> </association > <collection property ="student" ofType ="com.lcb.user.Student" > <id property ="id" column ="s_id" /> <result property ="name" column ="s_name" /> </collection > </resultMap > <select id ="getClass" parameterType ="int" resultMap ="ClassesResultMap" > select * from class c,teacher t where c.teacher_id=t.t_id and c.c_id=#{id} </select > <resultMap type ="com.lcb.user.Classes" id ="ClassesResultMap" > <id property ="id" column ="c_id" /> <result property ="name" column ="c_name" /> <association property ="teacher" javaType ="com.lcb.user.Teacher" > <id property ="id" column ="t_id" /> <result property ="name" column ="t_name" /> </association > </resultMap > </mapper >
Mybatis的分页原理 Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。
分页插件的原理就是使用MyBatis提供的插件接口,实现自定义插件,在插件的拦截方法内,拦截待执行的SQL,然后根据设置的dialect(方言),和设置的分页参数,重写SQL ,生成带有分页语句的SQL,执行重写后的SQL,从而实现分页。
举例:select ※ from student,拦截sql后重写为:select t.※ from (select ※ from student)t limit 0,10
1、内存分页(逻辑分页) 逻辑分页利用游标分页,好处是所有数据库都统一,坏处就是效率低。
使用 MyBatis 自带的 RowBounds 进行分页,它是一次性查询很多数据,然后在数据中再进行检索。
MyBatis使用RowBounds实现的分页是内存分页,也就是先把数据记录全部查询出来 , 然在再根据offset和limit截断记录返回(数据量大的时候会造成内存溢出 )
1 2 3 4 5 6 7 8 9 List<Honor> getHonorList (HashMap<String, Object> maps,RowBounds rowBounds) ; RowBounds(offset, pageSize); RowBounds rowBounds = new RowBounds (2 , 2 ); List<Honor> honors = studentMapper.getHonorList(maps,rowBounds);
2、物理分页 物理分页就是数据库本身提供了分页方式,如MySQL的limit,oracle的rownum ,好处是效率高,不好的地方就是不同数据库有不同的搞法。
自己手写 SQL 分页或使用分页插件 PageHelper,去数据库查询指定条数的分页数据的形式。
Mybatis动态SQL 传统的JDBC的方法,在组合SQL语句的时候需要去拼接,稍微不注意就会少少了一个空格,标点符号,都会导致系统错误。 Mybatis的动态SQL就是为了解决这种问题而产生的; Mybatis的动态SQL语句值基于OGNL表达式的,方便在SQL语句中实现某些逻辑; 可以使用标签组合成灵活的sql语句,提供开发的效率。
Mybatis的动态SQL标签主要由以下几类:
If 语句(简单的条件判断)
**Choose(when/otherwise)**,相当于java语言中的switch,
Trim (对包含的内容加上prefix,或者suffix)
Where (主要是用来简化SQL语句中where条件判断,能智能的处理and/or 不用担心多余的语法导致的错误)
Set (主要用于更新时候)
Foreach (一般使用在mybatis in语句查询时特别有用)
Mybatis的批量操作数据的方法 1、使用for循环在java代码中insert (不推荐)
2、foreach
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <insert id ="batchSave" parameterType ="java.util.List" > INSERT INTO lp_user_test_batch ( id, user_id, user_name, user_age, type, create_time, update_time ) VALUES <foreach collection ="list" item ="item" index ="index" separator ="," > ( #{item.id,jdbcType=BIGINT}, #{item.userId,jdbcType=VARCHAR}, #{item.userName,jdbcType=VARCHAR}, #{item.userAge,jdbcType=INTEGER}, #{item.type,jdbcType=INTEGER}, #{item.createTime,jdbcType=TIMESTAMP}, #{item.updateTime,jdbcType=TIMESTAMP} ) </foreach > </insert > <select id ="getList" resultType ="com.epeit.api.model.Device" > SELECT * FROM devcie WHERE 1=1 <if test ="ids != null and ids.size > 0" > AND id IN <foreach collection ="ids" item ="item" open ="(" separator ="," close =")" > #{item} </foreach > </if > </select >
批量新增或更新方式 注:需要给唯一主键添加唯一索引,update才会生效
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <insert id ="batchSaveOrUpdate" parameterType ="java.util.List" > INSERT INTO lp_user_test_batch ( id, user_id, user_name, user_age, type, create_time, update_time ) VALUES <foreach collection ="list" item ="item" index ="index" separator ="," > ( #{item.id,jdbcType=BIGINT}, #{item.userId,jdbcType=VARCHAR}, #{item.userName,jdbcType=VARCHAR}, #{item.userAge,jdbcType=INTEGER}, #{item.type,jdbcType=INTEGER}, #{item.createTime,jdbcType=TIMESTAMP}, #{item.updateTime,jdbcType=TIMESTAMP} ) </foreach > ON DUPLICATE KEY UPDATE user_name = VALUES(user_name), user_age = VALUES(user_age), type = VALUES(type), update_time = VALUES(update_time) </insert >
优点:速度快 缺点:使用特殊语法 on duplicate key update 语法 增加sql难度性