文章目录
- 1. 什么是 Mybatis ?
- 2. Mybatis 和 Hibernate 有哪些不同 ?
- 3. #{} 和 ${} 有什么不同 ?
- 4. 当实体类中的属性名和表中的字段名不一样 ,怎么办 ?
- 5. 模糊查询like语句该怎么写 ?
- 6. Mybatis是如何进行分页的?分页插件的原理是什么?
- 7. Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?
- 8. Mybatis 如何执行批量插入 ?
- 9. 如何获取自动生成的主键值 ?
- 10. 在 mapper 中如何传递多个参数 ?
- 11. Mapper 动态代理方式
- 12. Mybatis 动态 sql 有什么用 ? 执行原理 ? 有哪些动态 sql ?
- 13. xml 映射文件中,除了常见的 select、insert、update 和 delete 标签之外,还有哪些标签 ?
- 14. 为什么说 Mybatis 是半自动的 ORM 映射工具?它与全自动的区别在哪里 ?
- 15. 一对一、一对多关联查询 ?
- 16. Mybatis 是否支持延迟加载 ?如果支持,原理是什么 ?
- 17. Mybatis 的一级二级缓存
Mybatis
1. 什么是 Mybatis ?
(1)Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。程序员直接编写原生态sql,可以严格控制sql执行性能,灵活度高。
2. Mybatis 和 Hibernate 有哪些不同 ?
(1)Mybatis 和 Hibernate 不同,它不完全是一个 ORM 框架,因为 MyBatis 需要程序员自己编写 Sql 语句。Mybatis 可以通过 XML 或注解方式灵活配置要运行的sql语句,并将 Java 对象和 sql 语句映射生成最终执行的 sql,最后将 sql 执行的结果再映射生成 Java 对象。
(2)Mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。
(3)Hibernate对象/关系映射能力强,数据库无关性好。
3. #{} 和 ${} 有什么不同 ?
-
#{}
(1)表示一个占位符号,通过#{}可以实现 preparedStatement 向占位符中设置值
(2)自动进行java类型和jdbc类型转换
(3)#{}可以有效防止sql注入
(4)如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。 -
$ {}
(1)$ {}表示拼接sql串,通过 $ {}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换(2)$ {}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,$ {}括号中只能是value。
4. 当实体类中的属性名和表中的字段名不一样 ,怎么办 ?
- 通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。
<select id = ”selectorder” parametertype=”int” resultetype=”me.gacl.domain.order”>
select order_id id, order_no orderno ,order_price price form orders where order_id=#{id};
</select>
- 通过来映射字段名和实体类属性名的一一对应的关系。
<select id="getOrder" parameterType="int" resultMap="orderresultmap">
select * from orders where order_id=#{id}
</select>
<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>
5. 模糊查询like语句该怎么写 ?
- 在Java代码中添加sql通配符。
string wildcardname = “%smi%”;
list<name> names = mapper.selectlike(wildcardname);
<select id=”selectlike”>
select * from foo where bar like #{value}
</select>
- 在sql语句中拼接通配符,会引起sql注入
string wildcardname = “smi”;
list<name> names = mapper.selectlike(wildcardname);
<select id=”selectlike”>
select * from foo where bar like "%"${value}"%"
</select>
6. Mybatis是如何进行分页的?分页插件的原理是什么?
7. Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?
第一种是使用 标签,逐一定义数据库列名和对象属性名之间的映射关系。
第二种是使用 sql 列的别名功能,将别名书写为对象属性名。
有了列明和属性名的映射关系之后,Mybatis 通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性是无法完成赋值的。
8. Mybatis 如何执行批量插入 ?
首先创建一个简单的 insert 语句:
<insert id = "insertname">
insert into names (name) value (#{value})
</insert>
然后在 Java 代码中这样执行批量插入:
list<string> names = new arraylist();
names.add(“fred”);
names.add(“barney”);
names.add(“betty”);
names.add(“wilma”);
sqlsession sqlsession = sqlsessionfactory.opensession(executortype.batch);
namemapper mapper = sqlsession.getmapper(namemapper.class);
for (string name : names) {
mapper.insertname(name);
9. 如何获取自动生成的主键值 ?
insrt 方法总是返回一个 int 值,这个值代表的是插入的行数。
如果采用自增长策略,自动生成的键值在 insert 方法执行完后可以被设置到传入的参数对象中。
<insert id=”insertname” usegeneratedkeys=”true” keyproperty=”id”>
insert into names (name) values (#{name})
</insert>
name name = new name();
name.setname(“fred”);
int rows = mapper.insertname(name);
// 完成后,id已经被设置到对象中
system.out.println(“rows inserted = ” + rows);
system.out.println(“generated key value = ” + name.getid());
10. 在 mapper 中如何传递多个参数 ?
第一种:
//Dao 层的函数
public User selectUser(String name, String area);
//对应的xml,#{0}代表接收的是dao层中的第一个参数,#{1}代表dao层中第二参数,更多参数一致往后加即可。
<select id = "selectUser" resultMap = "BaseResultMap">
select * fromuser_user_t where user_name = #{0} and user_area=#{1}
</select>
11. Mapper 动态代理方式
Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
Mapper接口开发需要遵循以下规范:
- Mapper.xml文件中的namespace与mapper接口的类路径相同。
- Mapper 接口的方法名和 Mapper.xml 中定义的每个 statement 的 id 相同
- Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的 parameterType 的类型相同
- Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的 resultType 的类型相同
12. Mybatis 动态 sql 有什么用 ? 执行原理 ? 有哪些动态 sql ?
Mybatis 动态 sql 可以在 xml 映射文件内,以标签的形式编写动态的 sql。执行原理是根据表达式的值完成逻辑判断并动态拼接 sql。
Mybatis提供了9种动态sql标签:trim | where | set | foreach | if | choose | when | otherwise | bind。
13. xml 映射文件中,除了常见的 select、insert、update 和 delete 标签之外,还有哪些标签 ?
、、、、,加上动态sql的9个标签,其中为sql片段标签,通过标签引入sql片段,为不支持自增的主键生成策略标签。
14. 为什么说 Mybatis 是半自动的 ORM 映射工具?它与全自动的区别在哪里 ?
Hibernate 属于全自动的 ORM 映射工具, 使用Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。而Mybatis在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以,称之为半自动ORM映射工具。
15. 一对一、一对多关联查询 ?
一对一查询
- 比如,一个订单只能是一个人下的,所以从查询订单信心出发关联查询用户信息为一对一查询。如果从用户信息出发查询用户下的订单信息则为一对多查询。
- 方法一:使用resultType。使用resultType,改造订单pojo类,此pojo类中包括了订单信息和用户信息这样返回对象的时候,mybatis自动把用户信息也注入进来了。
- 方法二:使用resultMap。使用resultMap,定义专门的resultMap用于映射一对一查询结果。
一对多查询
16. Mybatis 是否支持延迟加载 ?如果支持,原理是什么 ?
Mybatis 仅支持 association 关联对象和 collection 关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。
它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。
17. Mybatis 的一级二级缓存
Mybatis缓存
缓存的重要性是不言而喻的。 使用缓存, 我们可以避免频繁的与数据库进行交互, 尤其是在查询越多、缓存命中率越高的情况下, 使用缓存对性能的提高更明显。
mybatis 也提供了对缓存的支持, 分为一级缓存和二级缓存。 但是在默认的情况下, 只开启一级缓存(一级缓存是对同一个 SqlSession 而言的)。
同一个 SqlSession 对象, 在参数和 SQL 完全一样的情况先, 只执行一次 SQL 语句(如果缓存没有过期)。
在日志和输出中:
第一次查询发送了 SQL 语句, 后返回了结果;
第二次查询没有发送 SQL 语句, 直接从内存中获取了结果。
而且两次结果输入一致, 同时断言两个对象相同也通过。
总结:
- 在同一个 SqlSession 中, Mybatis 会把执行的方法和参数通过算法生成缓存的键值, 将键值和结果存放在一个 Map 中, 如果后续的键值一样, 则直接从 Map 中获取数据;
- 不同的 SqlSession 之间的缓存是相互隔离的;
- 用一个 SqlSession, 可以通过配置使得在查询前清空缓存;
- 任何的 UPDATE, INSERT, DELETE 语句都会清空缓存。