MyBatis
1、MyBatis 是什么框架?
MyBatis是一个优秀的持久层框架
,它对jdbc的操作数据库的过程
进行封装
,使开发者只需要关注 SQL 本身
,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索
等jdbc繁杂的过程代码。
Mybatis通过xml或注解的方式
将要执行的各种statement(statement、preparedStatemnt)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
2、MyBatis 和 ORM 的区别?
3、MyBatis 为什么是半自动 ORM 映射?
Hibernate 属于全自动 ORM 映射工具
,使用 Hibernate 查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取
,所以它是全自动的。而 Mybatis 在查询关联对象或关联集合对象时,需要手动编写 sql
来完成,所以,称之为半自动 ORM 映射工具
。
4、MyBatis 框架的应用场景?
MyBatis 专注于 SQL 本身,是一个足够灵活的 DAO 层解决方案。
对性能的要求很高,或者需求变化较多的项目,如互联网项目,MyBatis 将是不错的选择。
5、MyBatis 有哪些优点?
优点
1.与JDBC相比,减少了50%以上的代码量。
2.MyBatis是最简单的持久层框架,小巧并且简单易学。
3.提供映射标签,支持对象与数据库的ORM字段关系映射。
4.提供XML标签,支持编写动态SQL语句。
6、MyBatis 有哪些缺点?
缺点
1.SQL语句编写工作量较大,对开发人员有一定的SQL语句功底要求。
2.SQL语句依赖于数据库,不能随便更改。
7、MyBatis 和 Hibernate 的区别?
hibernate是全自动,而mybatis是半自动
。
hibernate完全可以自动生成sql。而mybatis仅有基本的字段映射,仍然需要通过手写sql来实现和管理。
hibernate数据库移植性远大于mybatis
。
hibernate通过它强大的映射结构和hql语言,大大降低了对象与数据库(oracle、mysql等)的耦合性,
而mybatis由于需要手写sql,移植性也会随之降低很多,成本很高。
hibernate拥有完整的日志系统,mybatis则欠缺一些
。
hibernate日志系统非常健全,涉及广泛,而mybatis则除了基本记录功能外,功能薄弱很多。
mybatis相比hibernate需要关心很多细节
hibernate配置要比mybatis复杂的多,学习成本也比mybatis高。但也正因为mybatis使用简单,
才导致它要比hibernate关心很多技术细节。mybatis由于不用考虑很多细节,开发模式上与传统jdbc区别很小,
hibernate则正好与之相反。但是如果使用hibernate很熟练的话,实际上开发效率丝毫不差于甚至超越mybatis。
sql直接优化上,mybatis要比hibernate方便很多
由于mybatis的sql都是写在xml里,因此优化sql比hibernate方便很多。而hibernate的sql很多都是自动生成的,
无法直接维护sql;总之写sql的灵活度上hibernate不及mybatis。
8、MyBatis 和 JPA 的区别?
首先,Spring Data JPA可以理解为 JPA 规范的再次封装抽象
,底层还是使用了 Hibernate 的 JPA 技术实现
。
JPA默认使用hibernate作为ORM实现,所以,一般使用Spring Data JPA即会使用hibernate
。Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装
,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行
,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。
所以,这里说 jap和mybatis的区别也就是 hibernate和mybatis的区别了。
9、MyBatis 有哪几种 SQL 编写形式?
三种
在mapper文件中配置SQL
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis//DTD Mapper 3.0//EN"
"http://mybatis/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.test.cis.dao.accounts.FinanceRefundApplyDao">
<select id="queryById" resultType="FinanceRefundApplyModel" parameterType="String">
select * from FINANCE_REFUND_APPLY where ID = #{id}
</select>
</mapper>
注解式的SQL定义
public interface UserMapper {
@Select("select * from user ")
List<User> AnnotationGetUserList();
}
如果想要的是动态SQL,那么就加上<script>
:
public interface UserMapper {
@Select("select * from user ")
List<User> AnnotationGetUserList();
@Select("<script>"
+ "select * from user "
+ "<if test='id!=null'>"
+ "where id=#{id}"
+ "</if>"
+ "</script>")
List<User> AnnotationGetUserById(@Param("id")String id);
}
3.通过@SelectProvider
来声明sql提供类
public interface UserMapper {
@SelectProvider(type=SqlProvider.class,method="getUserById")
List<User> AnnotationProviderGetUserById(String id);
}
public class SqlProvider {
public String getUserById(String id) {
String sql = "select * from user ";
if (id!=null) {
sql += " where id="+id;
}
return sql;
}
}
10、MyBatis 支持哪些传参数的方法?
方式一、顺序传递参数
mapper.java文件:
public User selectUser(String name, int deptId);
mapper.xml文件:
<select id="selectUser" resultType="com.wyj.entity.po.User">
select * from user where userName = #{0} and deptId = #{1}
</select>
注意:里面的数字代表你传入参数的顺序,不是特别建议使用这种方法传递参数,特别是参数个数多的时候
方式二、注解@Param传递参数
mapper.java文件:
public User selectUser(@Param("userName") String name, int @Param("deptId") id);
mapper.xml文件:
<select id="selectUser" resultType="com.wyj.entity.po.User">
select * from user where userName = #{userName} and deptId = #{deptId}
</select>
注意:在xml文件中就只能以在@Param注解中声明的参数名称获取参数
方式三、使用Map集合传递参数
mapper.java文件:
public User selectUser(Map<String, Object> params);
mapper.xml文件:
<select id="selectUser" parameterType="java.util.Map" resultType="com.wyj.entity.po.User">
select * from user where userName = #{userName} and deptId = #{deptId}
</select>
方式四、使用JavaBean实体类传递参数
mapper.java文件:
public User selectUser(User user);
mapper.xml文件:
<select id="selectUser" parameterType="com.wyj.entity.po.User" resultType="com.wyj.entity.po.User">
select * from user where userName = #{userName} and deptId = #{deptId}
</select>
11、MyBatis 的 $ 和 # 传参的区别?
区别一: #传过来的数据会自动加上引号,$则不会
;
区别二: ${} 容易被sql注入,#{} 安全,
安全问题怎么理解?
#{}:解析为一个 JDBC 预编译语句(prepared statement)的参数标记符。#{} 相当于一个占位符,使用占位符,防止sql注入。
${}:取出的值会直接拼装在sql中,会有安全问题。
12、MyBatis 可以映射到枚举类吗?
Mybatis 可以映射枚举类。
可以,需要自定义对枚举类的类型转换器。例如写一个类为EnumTypeHandler继承BaseTypeHandler<枚举类型>,重写其中的方法,在getNullableResult方法中更具返回结果做响应的转换操作。
13、MyBatis 怎么封装动态 SQL?
映射方式
1、当列名和封装查询结果的类的属性名一一对应时
:
这时MyBatis 有自动映射功能
,将查询的记录封装到resultType 指定的类的对象中去
<mapper namespace="com.hanT.dao.UserDao">
<!--id对应接口中的方法名,resultType为返回结果的类型,要用类的全限定名-->
<select id="getUserList" resultType="com.hanT.pojo.User">
select * from mybatis.user
</select>
</mapper>
2、当列名和封装查询结果的类的属性名不对应时
:
使用resultMap
标签,在标签中配置属性名和列名的映射关系
<resultMap type="cn.mybatis.pojo.User" id="UserResult">
<result property="username" column="name"/>
</resultMap>
<select id="findUserById" parameterType="java.lang.Long" resultMap="UserResult">
select id,name,email from t_user where id=#{id}
</select>
14、Mybatis trim 标签有什么用?
1.<trim prefix="" suffix="" suffixOverrides="" prefixOverrides=""></trim>
prefix:在trim标签内sql语句加上前缀。
suffix:在trim标签内sql语句加上后缀。
suffixOverrides:指定去除多余的后缀内容,如:suffixOverrides=“,”,去除trim标签内sql语句多余的后缀","。
prefixOverrides:指定去除多余的前缀内容
2.下面是一个往购物车表中插入数据的mybatis语句
<insert id="insert" parameterType="com.tortuousroad.groupon.cart.entity.Cart">
insert into cart
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="userId != null">
user_id,
</if>
<if test="dealId != null">
deal_id,
</if>
<if test="dealSkuId != null">
deal_sku_id,
</if>
<if test="count != null">
count,
</if>
<if test="createTime != null">
create_time,
</if>
<if test="updateTime != null">
update_time,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=BIGINT},
</if>
<if test="userId != null">
#{userId,jdbcType=BIGINT},
</if>
<if test="dealId != null">
#{dealId,jdbcType=BIGINT},
</if>
<if test="dealSkuId != null">
#{dealSkuId,jdbcType=BIGINT},
</if>
<if test="count != null">
#{count,jdbcType=INTEGER},
</if>
<if test="createTime != null">
#{createTime,jdbcType=TIMESTAMP},
</if>
<if test="updateTime != null">
#{updateTime,jdbcType=TIMESTAMP},
</if>
</trim>
</insert>
15、MyBatis 怎么实现分页?
1、使用SQL的LIMIT做分页,分页参数可以使用Mybatis提供的Page封装,传给Mapper。
然后使用LIMIT (page-1)*size,size方式查询数据
2、使用PageHelper插件实现
3、使用Mybatis的Interceptor拦截器实现
16、MyBatis 流式查询有什么用?
流式查询指的是查询成功后不是返回一个集合
而是返回一个迭代器
,应用每次从迭代器取一条查询结果。流式查询的好处是能够降低内存使用。
如果没有流式查询,我们想要从数据库取 1000 万条记录而又没有足够的内存时,就不得不分页查询,而分页查询效率取决于表设计,如果设计的不好,就无法执行高效的分页查询。因此流式查询是一个数据库访问框架必须具备的功能。
流式查询的过程当中,数据库连接是保持打开状态的,因此要注意的是:执行一个流式查询后,数据库访问框架就不负责关闭数据库连接了,需要应用在取完数据后自己关闭。
17、MyBatis 模糊查询 like 语句该怎么写?
(1)直接传参法
直接传参法,就是将要查询的关键字keyword,在代码中拼接好要查询的格式,如%keyword%,然后直接作为参数传入mapper.xml的映射文件中。
public void selectBykeyWord(String keyword) {
String id = "%" + keyword + "%";
String roleType = "%" + keyword + "%";
String roleName = "%" + keyword + "%";
userDao.selectBykeyWord(id,roleName,roleType);
}
<select id="selectBykeyWord" parameterType="string" resultType="com.why.mybatis.entity.RoleEntity">
SELECT * FROM t_role WHERE role_name LIKE #{roleName}
OR id LIKE #{id}
OR role_type LIKE #{roleType}
</select>
注意:此方法可以完成模糊查询任务,但是不推荐,因为与Java代码耦合了,不利于维护和修改。
(2)mysql的CONCAT()函数
MySQL的CONCAT()函数用于将多个字符串连接成一个字符串,是最重要的mysql函数之一。用法:CONCAT(str1,str2,…)
<select id="selectBykeyWord" parameterType="string" resultType="com.why.mybatis.entity.RoleEntity">
SELECT * FROM t_role WHERE role_name LIKE CONCAT('%',#{keyword},'%')
OR id LIKE CONCAT('%',#{keyword},'%')
OR role_type LIKE CONCAT('%',#{keyword},'%')
</select>
注意:执行效果与上面的直接传参一样,但比直接传参法更好,因为与代码解耦了,但是此方法只针对mysql数据库所用,如果换成Oracle数据库则需要修改sql代码,因此此方法不通用,但可以使用。
(3)mybatis的bind元素
mybatis针对这种情况作出了调整,提供了一个bind元素,此元素可以跨越数据库限制
,也就是说不管是mysql还是Oracle数据库都可以通用模糊查询。
dao层接口如下:
List<RoleEntity> selectBykeyWord(@Param("keyword") String keyword);
mapper文件如下:
<select id="selectBykeyWord" parameterType="string" resultType="com.why.mybatis.entity.RoleEntity">
<!--keyword就是传入的参数,bind相当于是一个参数,这个参数的值就是value拼接出来的值-->
<bind name="pattern" value="'%' + keyword + '%'" />
SELECT * FROM t_role WHERE role_name LIKE #{pattern}
OR id LIKE #{pattern} OR role_type like #{pattern}
</select>
18、MyBatis 配置文件中的 SQL id 是否能重复?
可以重复,但是需要映射文件的namespace不同
;
19、MyBatis 如何防止 SQL 注入?
1、使用#{}来设置参数
2、正则表达式过滤非法字符
20、MyBatis 如何获取自动生成的主键id?
1、XML配置文件
<insert id="insert" parameterType="Person" useGeneratedKeys="true" keyProperty="id">
insert into person(name,pswd) values(#{name},#{pswd})
</insert>
2、Mapper中的方法
int insert(Person person);
注意在调用这个方法时,返回的int值并不是主键,而是插入的记录数
。主键id会被赋值到输入的person对象里,自动赋值给person对象的id属性。比如:
Person person = new Person("name","psw");
//num是插入的记录数
int num = PersonMapper.insert(person);
//person对象的id属性会变成自生成的id
int id = person.getId();
21、MyBatis 使用了哪些设计模式?
Builder模式,例如SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、
XMLStatementBuilder、 CacheBuilder;
工厂模式,例如SqlSessionFactory、ObjectFactory、MapperProxyFactory;
单例模式,例如ErrorContext和LogFactory;
代理模式,Mybatis实现的核心,比如MapperProxy、ConnectionLogger,
用的jdk的动态代理;还有executor.loader包使用了cglib或者javassist达到延迟加载的效果;
组合模式,例如SqlNode和各个子类ChooseSqlNode等;
模板方法模式,例如BaseExecutor和SimpleExecutor,还有BaseTypeHandler和所有的子类例如IntegerTypeHandler;
适配器模式,例如Log的Mybatis接口和它对jdbc、log4j等各种日志框架的适配实现;
22、MyBatis 中的缓存机制有啥用?
做服务器的进程内部缓存,提高查询效率,降低数据库访问频率
。Mybatis有三种缓存,一级缓存、二级缓存、第三方缓存EhCache,一级缓存时默认开启的,作用域时SqlSession
。二级缓存默认关闭需要在配置中使用enableCache="true"
开启,二级缓存时namespace作用域
的。第三方缓存需要引入额外Jar包,并且在配置中开启二级缓存开关,配置第三方缓存的核心类。
二级缓存是SqlSessionFactory的缓存
。只要是同一个SqlSessionFactory创建的SqlSession就共享二级缓存的内容,并且可以操作二级缓存.
23、MyBatis 一级缓存和二级缓存的区别?
1、作用域不同:
一级缓存的作用域是SqlSession级别的Map
,二级缓存是namespace级别的,也叫全局缓存
2、默认配置不同
一级缓存默认开启,二级缓存默认关闭
,需要在mybatis.cfg.xml配置文件中开启
<settings>
<setting name="cacheEnabled" value="true"/>
</settings
24、MyBatis-Plus 是什么框架?
Mybatis的增强框架
,帮助开发人员更加简化开发
。这些框架提供了大部分的简单SQL语句封装的API
,提供了分页插件,简化了配置流程。
不过只对单表有好的支持,多表关联查询支持差,一般需要手动编写多表的SQL,不过可以原生和增强一起使用。
25、mybatis延迟加载
延迟加载:就是在需要用到数据时才进行加载
,不需要用到数据时就不加载数据。延迟加载也称懒加载.
懒加载的配置
● 局部懒加载: 在association标签或者collection标签中,设置fetchType属性的值为lazy
<resultMap id="empAndDeptByStepResultMap" type="Emp">
<id property="eid" column="eid"></id>
<result property="empName" column="emp_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="email" column="email"></result>
<association property="dept"
select="com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
column="did"
fetchType="lazy"></association>
</resultMap>
● 全局懒加载: 在mybatis的核心配置文件中添加
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
更多推荐
MyBatis面试题(2022最新版)
发布评论