1 Star 0 Fork 31

阿明 / Ebooks

forked from Java精选 / Ebooks 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
2021年MyBaits面试题大汇总附答案.md 17.28 KB
一键复制 编辑 原始数据 按行查看 历史

2021年MyBaits面试题大汇总附答案

全部面试题答案,更新日期:01月30日,直接下载吧!

下载链接:高清500+份面试题资料及电子书,累计 10000+ 页大厂面试题 PDF

MyBaits

题1:Mybatis 中如何防止 SQL 注入的?

首先看一下下面两个sql语句的区别:

<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>

mybatis中#和$的区别:

#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。 如: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注入攻击。 在MyBatis中,“${xxx}”这样格式的参数会直接参与SQL编译,从而不能避免注入攻击。但涉及到动态表名和列名时,只能使用“${xxx}”这样的参数格式。所以,这样的参数需要我们在代码中手工进行处理来防止注入。 sql注入:

SQL注入,大家都不陌生,是一种常见的攻击方式。攻击者在界面的表单信息或URL上输入一些奇怪的SQL片段(例如“or '1'='1'”这样的语句),有可能入侵参数检验不足的应用程序。所以,在应用中需要做一些工作,来防备这样的攻击方式。在一些安全性要求很高的应用中(比如银行软件),经常使用将SQL语句全部替换为存储过程这样的方式,来防止SQL注入。这当然是一种很安全的方式,但平时开发中,可能不需要这种死板的方式。

mybatis是如何做到防止sql注入的?

MyBatis框架作为一款半自动化的持久层框架,其SQL语句都要自己手动编写,这个时候当然需要防止SQL注入。其实,MyBatis的SQL是一个具有“输入+输出”的功能,类似于函数的结构,参考上面的两个例子。其中,parameterType表示了输入的参数类型,resultType表示了输出的参数类型。回应上文,如果我们想防止SQL注入,理所当然地要在输入参数上下功夫。上面代码中使用#的即输入参数在SQL中拼接的部分,传入参数后,打印出执行的SQL语句,会看到SQL是这样的:

select id, username, password from user where username=? and password=?

不管输入什么参数,打印出的SQL都是这样的。这是因为MyBatis启用了预编译功能,在SQL执行前,会先将上面的SQL发送给数据库进行编译;执行时,直接使用编译好的SQL,替换占位符“?”就可以了。因为SQL注入只能对编译过程起作用,所以这样的方式就很好地避免了SQL注入的问题。

底层实现原理

MyBatis是如何做到SQL预编译的呢?其实在框架底层,是JDBC中的PreparedStatement类在起作用,PreparedStatement是我们很熟悉的Statement的子类,它的对象包含了编译好的SQL语句。这种“准备好”的方式不仅能提高安全性,而且在多次执行同一个SQL时,能够提高效率。原因是SQL已编译好,再次执行时无需再编译。 结论:

#{}:相当于JDBC中的PreparedStatement ${}:是输出变量的值

简单说,#{}是经过预编译的,是安全的;${}是未经过预编译的,仅仅是取变量的值,是非安全的,存在SQL注入。

题2:Mybatis 中分页插件的原理是什么?

Mybatis分页插件的基本原理是使用mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。

题3:Mybatis 中 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="对象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接口:

① mapper.xml中的namespace为mapper接口的地址

② mapper接口中的方法名和mapper.xml中的定义的statement的id保持一致

③ 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 name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>

4)使用扫描器后从spring容器中获取mapper的实现对象。

题4:MyBatis 是否支持延迟加载?其原理是什么?

Mybatis支持association关联对象和collection关联集合对象的延迟加载。

association指的就是一对一 collection指的就是一对多查询

在Mybatis配置文件中,启用延迟加载配置参数

lazyLoadingEnabled=true。

原理:使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法。

比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,就会单独发送事先保存好的查询关联B对象的SQL语句,先查询出B,然后再调用a.setB(b)赋值,最后再调用a.getB().getName()方法就有值了。几乎所有的包括Hibernate、Mybatis,支持延迟加载的原理都是一样的。

题5:MyBatis 中 mapper 如何实现传递多个参数?

方式一:

1)DAO层的函数

Public UserselectUser(String name,String area);

2)对应的xml,#{0}代表接收的是dao层中的第一个参数,#{1}代表dao层中第二参数,更多参数一致往后加即可。

<select id="selectUser"resultMap="BaseResultMap">  
    select *  fromuser_user_t   whereuser_name = #{0} anduser_area=#{1}  
</select>  

方式二:使用 @param 注解

public interface Usermapper {
   user selectuser(@param("username") string username,@param("hashedpassword") string hashedpassword);
}

之后就可以在xml像下面这样使用(推荐第三种方式封装为map集合,作为单个参数传递给mapper): select id, username, hashedpassword from some_table where username = #{username} and hashedpassword = #{hashedpassword}

方式三:多个参数封装成map

try{
//映射文件的命名空间.SQL片段的ID,就可以调用对应的映射文件中的SQL
//由于其参数超过了两个,而方法中只有一个Object参数收集,因此使用Map集合来装载所需的参数。
Map<String, Object> map = new HashMap();
     map.put("start", start);
     map.put("end", end);
     return sqlSession.selectList("StudentID.pagination", map);
 }catch(Exception e){
     e.printStackTrace();
     sqlSession.rollback();
    throw e; }
finally{
    MybatisUtil.closeSqlSession();
 }

题6:MyBatis 如何实现分页?

Mybatis使用rowbounds对象进行分页,它是针对resultset结果集执行的内存分页,而非物理分页。可以在sql内直接带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。

对数据库表数据进行分页,依靠offset和limit两个参数,表示从第几条开始,取多少条。也就是常说的start和limit。

1)相对原始方法,使用limit分页,需要处理分页逻辑:

MySQL数据库使用limit,如:

select * from table limit 0,10; --返回0-10行

Oracle数据库使用rownum,如:

从表Sys_option(主键为sys_id)中从第10条记录开始检索20条记录,语句如下:

SELECT * FROM (SELECT ROWNUM R,t1.* From Sys_option where rownum < 30 ) t2 Where t2.R >= 10

2)拦截StatementHandler,其实质还是在最后生成limit语句。

3)使用PageHelper插件,目前比较常见的方法。

题7:MyBatis 中 模糊查询 like 语句如何使用?

方式一:Java代码中添加sql通配符

String mname = "%Java精选,微信公众号%";
List<UserInfo> list = mapper.selectUserInfo(mnane);
<select id="selectUserInfo">

    select * from t_userinfo where name like #{mname}

</select>

方式二:sql语句中拼接通配符

String name = "Java精选,微信公众号";
List<UserInfo> list = mapper.selectUserInfo(nane);
<select id="selectUserInfo">

    select * from t_userinfo where name like '%${name}%'

</select>

sql语句中拼接通配符需要注意sql注入的问题,在参数放入sql语句前校验是否合法。

题8:为什么说 MyBatis 是半自动 ORM 映射?

ORM是Object和Relation之间的映射,包括Object->Relation和Relation->Object两方面。Hibernate是个完整的ORM框架,而MyBatis完成的是Relation->Object,也就是其所说的Data Mapper Framework。

JPA是ORM映射标准,主流的ORM映射都实现了这个标准。MyBatis没有实现JPA,它和ORM框架的设计思路不完全一样。MyBatis是拥抱SQL,而ORM则更靠近面向对象,不建议写SQL,实在要写需用框架自带的类SQL代替。MyBatis是SQL映射而不是ORMORM映射,当然ORM和MyBatis都是持久层框架。

最典型的ORM映射是Hibernate,它是全自动ORM映射,而MyBatis是半自动的ORM映射。Hibernate完全可以通过对象关系模型实现对数据库的操作,拥有完整的JavaBean对象与数据库的映射结构来自动生成SQL。而MyBatis仅有基本的字段映射,对象数据以及对象实际关系仍然需要通过手写SQL来实现和管理。

Hibernate数据库移植性远大于MyBatis。Hibernate通过它强大的映射结构和HQL语言,大大降低了对象与数据库(oracle、mySQL等)的耦合性,而MyBatis由于需要手写SQL,因此与数据库的耦合性直接取决于程序员写SQL的方法,如果SQL不具通用性而用了很多某数据库特性的SQL语句的话,移植性也会随之降低很多,成本很高。

题9:通常一个mapper.xml文件,都会对应一个Dao接口,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?

Mapper接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Mapper接口生成代理对象proxy,代理对象会拦截接口方法,根据类的全限定名+方法名,唯一定位到一个MapperStatement并调用执行器执行所代表的sql,然后将sql执行结果返回。

Mapper接口里的方法,是不能重载的,因为是使用 全限名+方法名 的保存和寻找策略。

Dao接口即Mapper接口。接口的全限名,就是映射文件中的namespace的值;接口的方法名,就是映射文件中Mapper的Statement的id值;接口方法内的参数,就是传递给sql的参数。

当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MapperStatement。在Mybatis中,每一个SQL标签,都会被解析为一个MapperStatement对象。

举例:com.mybatis3.mappers.StudentDao.findStudentById,可以唯一找到namespace为com.mybatis3.mappers.StudentDao下面 id 为 findStudentById 的 MapperStatement。

题10:MyBatis 实现批量插入数据的方式有几种?

MyBatis 实现批量插入数据的方式有几种?

1、MyBatis foreach标签

foreach主要用在构建in条件,在SQL语句中进行迭代一个集合。

foreach元素的属性主要有item,index,collection,open,separator,close。

item表示集合中每一个元素进行迭代时的别名 index指定一个名字,用于表示在迭代过程中,每次迭代到的位置 open表示该语句以什么开始 separator表示在每次进行迭代之间以什么符号作为分隔符 close表示以什么结束

collection必须指定该属性,在不同情况下,值是不同的,主要体现3种情况:

若传入单参数且参数类型是List时,collection属性值为list

若传入单参数且参数类型是array数组时,collection的属性值为array

若传入参数是多个时,需要封装成Map

具体用法如下:

<insert id="insertForeach" parameterType="java.util.List" useGeneratedKeys="false">
	insert into t_userinfo
	(name, age, sex) values
	<foreach collection="list" item="item" index="index" separator=",">
		(#{item.name},#{item.age},#{item.sex})
	</foreach>		
</insert>

2、MyBatis ExecutorType.BATCH

Mybatis内置ExecutorType,默认是simple,该模式下它为每个语句的执行创建一个新的预处理语句,单条提交sql。

batch模式会重复使用已经预处理的语句,并批量执行所有更新语句。但batch模式Insert操作时,在事务没有提交前,是无法获取到自增的id。

题11:mybatis-中不同的-xml-映射文件-id-是否可以重复

题12:mybatis-和-hibernate-都有哪些区别

题13:mybatis-中-mapper-接口调用时有哪些要求

题14:mybatis-中如何解决实体类属性名和表字段名不一致问题

题15:mybatis映射文件中a标签使用include引用b标签内容b标签能否定义在a标签的后面还是说必须定义在a标签的前面

题16:如何解决-mybatis-转义字符的问题

题17:mybatis-中实现一对多关系有几种方式

题18:mybatis-中如何获取自动生成的主键值

题19:mybatis-中有哪些动态-sql-标签有什么作用

题20:mybatis-中-integer-类型值是-0-为什么-!=-''-无法执行

题21:mybatis-中如何指定使用哪种-executor-执行器

题22:mybatis-中-mapper-编写有哪几种方式

题23:mybatis-是否可以映射-enum-枚举类

题24:xml-映射文件中除了常见的标签外还有哪些

题25:mybatis-是什么框架

大厂面试题

大厂面试题

大厂面试题

Java
1
https://gitee.com/AminDev/ebooks.git
git@gitee.com:AminDev/ebooks.git
AminDev
ebooks
Ebooks
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891