1.mybatis 中 #{}和 ${}的区别是什么?
1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by "111", 如果传入的值是id,则解析成的sql为order by "id".
2. $将传入的数据直接显示生成在sql中。如:order by $user_id$,如果传入的值是111,那么解析成sql时的值为order by user_id, 如果传入的值是id,则解析成的sql为order by id.
3. #方式能够很大程度防止sql注入。
4.$方式无法防止Sql注入。
5.$方式一般用于传入数据库对象,例如传入表名.
6.一般能用#的就别用$.
但是MyBatis排序时使用order by 动态参数时需要注意,用$而不是#
2.mybatis 有几种分页方式? mybatis 分页插件的实现原理是什么?
mybatis框架分页实现,有几种方式,最简单的就是利用原生的sql关键字limit来实现,还有一种就是利用interceptor来拼接sql,实现和limit一样的功能,再一个就是利用PageHelper分页插件来实现。这里讲解这三种常见的实现方式:无论哪种实现方式,我们返回的结果,不能再使用List了,需要一个自定义对象Pager。
分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数
3. Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?
第一种是使用<resultMap>标签,逐一定义数据库列名和对象属性名之间的映射关系。
第二种是使用sql列的别名功能,将列的别名书写为对象属性名。
有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
4.mybatis 逻辑分页和物理分页的区别是什么?
Mybatis可以通过传递RowBounds对象,来进行数据库数据的分页操作,然而遗憾的是,该分页操作是对ResultSet结果集进行分页,这就是逻辑分页
物理分页性能是最好的。下面就是物理分页的结果
1. Sql中带有offset,limit参数,自己控制参数值,直接查询分页结果。
2. 使用第三方开发的Mybatis分页插件。
3. 修改Mybatis源码,给Sql追加自己的物理分页Subsql。
1:逻辑分页 内存开销比较大,在数据量比较小的情况下效率比物理分页高;在数据量很大的情况下,内存开销过大,容易内存溢出,不建议使用
2:物理分页 内存开销比较小,在数据量比较小的情况下效率比逻辑分页还是低,在数据量很大的情况下,建议使用物理分页
5.mybatis 是否支持延迟加载?延迟加载的原理是什么?
在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()方法的调用。这就是延迟加载的基本原理。
当然了,不光是Mybatis,几乎所有的包括Hibernate,支持延迟加载的原理都是一样的。
6.说一下 mybatis 的一级缓存和二级缓存?
一级缓存:一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构用于存储缓存数据。不同的sqlSession之间的缓存数据区域是互相不影响的。也就是他只能作用在同一个sqlSession中,不同的sqlSession中的缓存是互相不能读取的。
二级缓存:二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。UserMapper有一个二级缓存区域(按namespace分),其它mapper也有自己的二级缓存区域(按namespace分)。每一个namespace的mapper都有一个二级缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同的二级缓存区域中。对于查询多commit少且用户对查询结果实时性要求不高,此时采用mybatis二级缓存技术降低数据库访问量,提高访问速度。
二级缓存性能不佳会造成问题:
1)对该表的操作与查询都在同一个namespace下,其他的namespace如果有操作,就会发生数据的脏读。
2)对关联表的查询,关联的所有表的操作都必须在同一个namespace。
所以一般情况下 mybatis的二级缓存默认关闭不太使用
7.mybatis 和 hibernate 的区别有哪些?
相同点:屏蔽jdbc api的底层访问细节,使用我们不用与jdbc api打交道,就可以访问数据。jdbc api编程流程固定,还将sql语句与java代码混杂在了一起,经常需要拼凑sql语句,细节很繁琐。
mybatis的好处:屏蔽jdbc api的底层访问细节;将sql语句与java代码进行分离;提供了将结果集自动封装称为实体对象和对象的集合的功能,queryForList返回对象集合,用queryForObject返回单个对象;提供了自动将实体对象的属性传递给sql语句的参数。
Hibernate是一个全自动的orm映射工具,它可以自动生成sql语句,mybatis需要我们自己在xml配置文件中写sql语句,hibernate要比mybatis功能负责和强大很多。因为hibernate自动生成sql语句,我们无法控制该语句,我们就无法去写特定的高效率的sql。对于一些不太复杂的sql查询,hibernate可以很好帮我们完成,但是,对于特别复杂的查询,hibernate就很难适应了,这时候用mybatis就是不错的选择,因为mybatis还是由我们自己写sql语句。
8.mybatis 有哪些执行器(Executor)?
SimpleExecutor、ReuseExecutor、BatchExecutor。
SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。
ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。简言之,就是重复使用Statement对象。
BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。
作用范围:Executor的这些特点,都严格限制在SqlSession生命周期范围内。
9.
MyBatis实现一对一有几种方式?具体怎么操作的?
MyBatis实现一对多有几种方式,怎么操作的?
一对一:
有联合查询和嵌套查询,联合查询是几个表联合查询,只查询一次, 通过在resultMap里面配置association节点配置一对一的类就可以完成;嵌套查询是先查一个表,根据这个表里面的结果的 外键id,去再另外一个表里面查询数据,也是通过association配置,但另外一个表的查询通过select属性配置。
一对多:
有联合查询和嵌套查询。联合查询是几个表联合查询,只查询一次,通过在resultMap里面的collection节点配置一对多的类就可以完成;嵌套查询是先查一个表,根据这个表里面的 结果的外键id,去再另外一个表里面查询数据,也是通过配置collection,但另外一个表的查询通过select节点配置。
10.mybatis 如何编写一个自定义插件?
1. 编写Interceptor的实现类 2. 使用@Intercepts注解完成插件签名 说明插件的拦截四大对象之一的哪一个对象的哪一个方法 3. 将写好的插件注册到全局配置文件中4大对象。
1.Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) --执行sql
2.ParameterHandler (getParameterObject, setParameters) --获取、设置参数
3.ResultSetHandler (handleResultSets, handleOutputParameters) --处理结果集
4.StatementHandler (prepare, parameterize, batch, update, query) --记录sql
11.简单介绍下你对MyBatis的理解?MyBatis中如何使用事务?MyBatis如何做对象关联?
1. MyBatis是一个数据持久层(ORM)框架。把实体类和SQL语句之间建立了映射关系,是一种半自动化的ORM实现。需要开发人员自己来写sql语句,程序更灵活,在一定程度上可以作为ORM的一种补充。数据库移植性差。便于统一管理与维护,降低了程序的耦合度
2. Mybatis对于事务的支持不太好。需要手动开启JDBC事务进行事务管理。在整个请求处理之前,创建事务工厂,基于同一个SqlSession对象获得事务对象,期间执行多次数据库更新操作,最后捕捉异常,进行事务回滚或关闭。
3. Mybatis的对象关联,分成:集合、关联
一对多,多对多统称为集合。多对一,一对一统称为关联。
不管是集合还是关联,都有两种实现方式:
嵌套查询:分别编写两个查询sql,通过自定义resultMap中association或者collection标签的select引用,将查询嵌套起来
嵌套结果:编写联表查询sql,查询出需要的多表中的数据,分别通过不同的resultMap进行映射,并在主resultMap的association或者collection标签的resultMap中,将结果映射嵌套起来
嵌套查询可能会出现1+N次查询的问题,可以通过延迟加载来尽量减少性能的影响。嵌套结果会使查询数据过多,并且不能延迟加载。所以通常使用嵌套查询更多些。
12.JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的?
① 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
解决:在SqlMapConfig.xml中配置数据链接池,使用连接池管理数据库链接。
② Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。
③ 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。
解决: Mybatis自动将java对象映射至sql语句。
④ 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
解决:Mybatis自动将sql执行结果映射至java对象。
13.MyBatis编程步骤是什么样的?
① 创建SqlSessionFactory
②通过SqlSessionFactory创建SqlSession
③ 通过sqlsession执行数据库操作
④ 调用session.commit()提交事务
⑤ 调用session.close()关闭会话
14.使用MyBatis的mapper接口调用时有哪些要求?
① Mapper接口方法名和mapper.xml中定义的每个sql的id相同
② Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
③ Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
④ Mapper.xml文件中的namespace即是mapper接口的类路径。
16.SqlMapConfig.xml中配置有哪些内容?
SqlMapConfig.xml中配置的内容和顺序如下:
properties(属性)
settings(配置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
17.Mapper编写有哪几种方式?
①接口实现类继承SqlSessionDaoSupport
使用此种方法需要编写mapper接口,mapper接口实现类、mapper.xml文件
1、在sqlMapConfig.xml中配置mapper.xml的位置
<mappers>
<mapper resource="mapper.xml文件的地址" />
<mapper resource="mapper.xml文件的地址" />
</mappers>
2、定义mapper接口
3、实现类集成SqlSessionDaoSupport
mapper方法中可以this.getSqlSession()进行数据增删改查。
4、spring 配置
<bean id=" " class="mapper接口的实现">
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
②使用org.mybatis.spring.mapper.MapperFactoryBean
1、在sqlMapConfig.xml中配置mapper.xml的位置
如果mapper.xml和mappre接口的名称相同且在同一个目录,这里可以不用配置
<mappers>
<mapper resource="mapper.xml文件的地址" />
<mapper resource="mapper.xml文件的地址" />
</mappers>
2、定义mapper接口
注意
1、mapper.xml中的namespace为mapper接口的地址
2、mapper接口中的方法名和mapper.xml中的定义的statement的id保持一致
3、 Spring中定义
<bean id="" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="mapper接口地址" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
③使用mapper扫描器
1、mapper.xml文件编写,
注意:
mapper.xml中的namespace为mapper接口的地址
mapper接口中的方法名和mapper.xml中的定义的statement的id保持一致
如果将mapper.xml和mapper接口的名称保持一致则不用在sqlMapConfig.xml中进行配置
2、定义mapper接口
注意mapper.xml的文件名和mapper的接口名称保持一致,且放在同一个目录
3、配置mapper扫描器
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="mapper接口包地址"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
4、使用扫描器后从spring容器中获取mapper的实现对象
扫描器将接口通过代理方法生成实现对象,要spring容器中自动注册,名称为mapper 接口的名称。
18.Mybaits动态查询(动态SQL)
有时候我们并不想应用所有的条件,而只是想从多个选项中选择一个。如果直接写静态的SQL语句,可能会引起SQL语句的报错,比如在where条件语句后面多了个,拼接等等,这时候就需要采用动态sql标签来拼接动态的SQl语句执行查询。Mybatis提供了9种动态sql标签:trim | where | set | foreach | if | choose | when | otherwise | bind。
If条件:<if>元素被用来有条件地嵌入SQL片段,如果测试条件被赋值为true, 则相应地SQL片段将会被添加到SQL语句中。
choose,when 和 otherwise 条件:有点类似于Java中的switch选择结构,我们【需要只使用其中一种】查询类别。
Where 条件:所有的查询条件应该是可选的。在需要使用至少一种查询条件的情况下,我们应该使用WHERE子句。并且如果有多个条件,我们需要在条件中添加AND或OR。 MyBatis提供了<where>元素支持这种类型的动态SQL语句。
<trim>条件:<trim>元素和<where>元素类似,但是<trim>提供了在添加前缀/后缀或者移除前缀/后缀方面提供更大的灵活性。
foreach 循环:另外一个强大的动态SQL语句构造标签即是<foreach>。它可以迭代遍历一个数组或者列表,构造AND/OR条件或一个IN子句。
set 条件:<set>元素和<where>元素类似,如果其内部条件判断有任何内容返回时,他会插入SET SQL 片段。
19.如何获取自动生成的(主)键值?
insert 方法总是返回一个int值 ,这个值代表的是插入的行数。
如果采用自增长策略,自动生成的键值在 insert 方法执行完后可以被设置到传入的参数对象中。
20.在mapper中如何传递多个参数?
未完待续。。。。将不定时更新
网友评论