(12)Mybatis框架
1 Mybatis的适用场景是什么?
MyBatis 是一款持久层框架和灵活的 DAO 层解决方案,它支持自定义 SQL、存储过程以及高级映射。MyBatis 可以处理项目中所有的JDBC 代码、设置参数和获取结果集的工作。通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO为数据库中的记录。MyBatis 专注于 SQL 本身,适合对性能的要求很高或者需求变化较多的项目,如Web项目。
2 MyBatis与Hibernate有哪些不同?
(1)相比Hibernate,Mybatis是个不完全的ORM框架,需要程序员自己编写Sql语句。
(2)Mybatis可以严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发。这类软件需求变化频繁,一但需求变化要求迅速输出成果。mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件,则需要自定义多套sql映射文件,工作量大。
(3)Hibernate对象关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用hibernate开发可以节省很多代码,提高效率。
3 Mybatis如何实现批量提交?
- mapper.xml使用foreach遍历
数据库连接属性添加allowMutiQueries=true
,例如:jdbc.url=jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true
<insert id="addEmpsBatch">
INSERT INTO emp(ename,gender,email,did)
VALUES
<foreach collection="emps" item="emp" separator=",">
(#{emp.eName},#{emp.gender},#{emp.email},#{emp.dept.id})
</foreach>
</insert>
- 开启事务提交
定义bean:
<!-- 配置一个可以批量执行的sqlSession -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"></constructor-arg>
<constructor-arg name="executorType" value="BATCH"></constructor-arg>
</bean>
定义mapper:
public interface EmployeeMapper {
//批量保存员工
public Long addEmp(Employee employee);
}
<mapper namespace="com.agesun.mybatis.dao.EmployeeMapper"
<!--批量保存员工 -->
<insert id="addEmp">
insert into employee(lastName,email,gender)
values(#{lastName},#{email},#{gender})
</insert>
</mapper>
实现service:
@Autowired
private SqlSession sqlSession;
@Override
public Integer batchEmp() {
//批量保存执行前时间
long start=System.currentTimeMillis();
EmployeeMapper mapper= sqlSession.getMapper(EmployeeMapper.class);
for (int i = 0; i < 10000; i++) {
mapper.addEmp(new Employee(UUID.randomUUID().toString().substring(0,5),"b","1"));
}
long end = System.currentTimeMillis();
long time = end-start;
return (int) time;
}
4 Mybatis有缓存吗?
一级缓存是基于会话(即SqlSession)层面的缓存,也被叫做本地缓存。主要是用于同一个数据库会话中,执行了多次相同的SQL语句的场景,在该场景下,如果SQL语句相同,则会优先从一级缓存中返回数据,避免直接查询数据库,从而提高查询性能。如果是在同一个会话中进行了增删改功能,则会清空一级缓存。Mybatis的一级缓存是默认开启的,不需要任何配置就能生效。
二级缓存用来解决一级缓存不能跨会话共享的问题,范围是基于mapper文件的namespace的,也 就 是说多个SqlSession可以共享一个mapper中的二级缓存区域,并且如果两个mapper的namespace 相 同,即使是两个mapper,那么这两个mapper中执行SQL查询到的数据也将存在相同的二级缓存区域中。和一级缓存不同,二级缓存默认不开启,需要手动进行开启。
5 #{}和${}的区别是什么?
(1)#{} 是预编译处理,${}是字符串替换。
(2)Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值。
(3)Mybatis在处理${}时,就是把${}替换成变量的值。
(4)使用#{}可以有效的防止SQL注入,提高系统安全性。
6 Mybatis如何解决SQL注入?
以下面的mapper.xml为例:
<select id="selectByNameAndPassword" parameterType="java.util.Map" resultMap="BaseResultMap">
select id, username, password
from user
where username = #{username,jdbcType=VARCHAR} and
password = #{password,jdbcType=VARCHAR}
</select>
<select id="selectByNameAndPassword" parameterType="java.util.Map" resultMap="BaseResultMap">
select id, username, password,
from user
where username = ${username,jdbcType=VARCHAR} and
password = ${password,jdbcType=VARCHAR}
</select>
字符#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。 如:where username=#{username}
,如果传入的值是111,那么解析成sql时的值为where username = "111"
, 如果传入的值是id,则解析成的sql为where username="id"。
字符$将传入的数据直接显示生成在sql中。如:where username = ${username}
,如果传入的值是111,那么解析成sql时的值为 where username=111
如果传入的值是:drop table user
;,则解析成的sql为: select id, username, password, role from user where username=;drop table user;
字符#方式能够很大程度防止sql注入,$方式无法防止Sql注入。一般能用#的就别用$,若不得不使用“${xxx}”这样的参数,要手工地做好过滤工作,来防止sql注入攻击。
参考(摘抄的文字版权属于原作者)
https://zhuanlan.zhihu.com/p/347935099