跳至主要內容

(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/347935099open in new window

上次编辑于: