1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > mybatis基础综合/常见面试题

mybatis基础综合/常见面试题

时间:2020-12-28 00:37:30

相关推荐

mybatis基础综合/常见面试题

概念/作用:

持久层框架,通过xml或注解的方式将要执行的各种 statement配置起来,并通过java对象和statement中sql的动态参数进行映射生成最终执行的sql语句。最后mybatis框架执行sql并将结果映射为java对象并返回。采用ORM思想解决了实体和数据库映射的问题,对jdbc 进行了封装,屏蔽了jdbc api 底层访问细节,使我们不用与jdbc api 打交道,就可以完成对数据库的持久化操作。

数据源环境environment可以配置多个

mapper文件里面配置了多个select/insert/update/delete sql语句,取用的时候是采用标识:namespace+id

默认事务不提交

Mybatis----多表操作

一对一查询,一个用户只有一个订单

对应的sql语句:select * from orders o,user u where o.uid=u.id;

user表和orders表连接,自然就需要user+order两个对象来映射返回的所有列

<mapper namespace="com.mapper.OrderMapper"><resultMap id="orderMap" type="com.domain.Order"><!--手动指定字段与实体属性的映射关系 column: 数据表的字段名称 property:实体的属性名称 --><id column="oid" property="id"></id><result column="ordertime" property="ordertime"></result><result column="total" property="total"></result>//主键使用id标签<id column="id" property="id"></id><result column="uid" property="user.id"></result><result column="username" property="user.username"></result><result column="password" property="user.password"></result><result column="birthday" property="user.birthday"></result></resultMap><select id="findAll" resultMap="orderMap">select * from orders o,user u where o.uid=u.id</select></mapper>

注解配置

首先核心配置文件中:

<mappers>

<!--扫描使用注解的类所在的包-->

<package name="com.mapper"></package>

</mappers>

在接口中进行sql语句的映射配置public interface UserMapper {@Insert("insert into user values(#{id},#{username},#{password},#{birthday})")public void save(User user);@Update("update user set username=#{username},password=#{password} where id=#{id}")public void update(User user);@Delete("delete from user where id=#{id}")public void delete(int id);@Select("select * from user where id=#{id}")public User findById(int id);@Select("select * from user")public List<User> findAll();@Select("select * from user")@Results({@Result(id=true ,column = "id",property = "id"),@Result(column = "username",property = "username"),@Result(column = "password",property = "password"),@Result(property = "orderList",column = "id",javaType = List.class,many = @Many(select = "com.mapper.OrderMapper.findByUid"))})public List<User> findUserAndOrderAll();上面等价与先在user表中查出uid 然后 在订单表中查询 select * from order where uid=user.uid@Select("SELECT * FROM USER")@Results({@Result(id = true,column = "id",property = "id"),@Result(column = "username",property = "username"),@Result(column = "password",property = "password"),@Result(property = "roleList",column = "id",javaType = List.class,many = @Many(select = "com.itheima.mapper.RoleMapper.findByUid"))})public List<User> findUserAndRoleAll();}

mybatis常见面试题:

具体问题

1、#{}和${}区别

都属于占位符

#{}是预编译处理使用prepareStatedment的参数设置方法;$ {}是字符串替换,参数传递

#{} :mybatis内部会创建配prepareStatedment 使用#{}格式的语法在mybatis中使用prepareStatedment语句来安全的设置值; MyBatis在处理#{}时,会将SQL中的#{}替换为?号,使用PreparedStatement的set方法来赋值;MyBatis在处理 $ { } 时,就是把 ${ } 替换成变量的值。

${}是 Properties 文件中的变量占位符,它可以用于标签属性值和 sql 内部,属于静态文本替换,比如${driver}会被静态替换为com.mysql.jdbc.Driver。

#{}sql的参数占位符,MyBatis 会将 sql 中的#{}替换为?号,sql执行前会使用PreparedStatement的参数设置方法,按序给 sql 的?号占位符设置参数值,比如 ps.setInt(0, parameterValue),#{item.name} 的取值方式为使用反射从参数对象中获取item对象的name属性值,相当于 param.getItem().getName()。

预编译是:指的是数据库驱动在发送 sql 语句和参数给 DBMS 之前对 sql 语句进行编译,这样 DBMS 执行 sql 时,就不需要重新编译。

2、mapper.xml 标签有哪些?resultMap和resultType的区别?

常用的<select> <delete> <insert> <update>,除此之外:

<resultMap>、<parameterMap>、<sql>、<include>、<selectKey>,加上动态 sql 的 9 个标签,trim|where|set|foreach|if|choose|when|otherwise|bind等,其中为 sql 片段标签,通过<include>标签引入 sql 片段,<selectKey>为不支持自增的主键生成策略标签。

resultMap 是一种"查询结果集---Bean对象”属性名称映射关系,列和bean对象的属性的映射,一般适用于多表连接

Resulttype---一般适用于pojo(简单对象)类型数据,简单的单表查询

如果配置成类,一般映射会遵循约定:要求Bean对象字段名和查询结果集的属性名相同(可以大小写不同,大小写不敏感)。因为这个自动映射,可以省略调resultMap进行属性名映射。也可以是int long这种pojo类型

3.dao接口的底层原理(如何返回实现类并且封装好结果集合的)?

通过动态代理实现接口的实现类,在mapperPorxy(实现invocationHandler接口)中的invoke中调用sql语句:mapperMethod.execute(sqlSession, args);

===》会进行paramname解析 比如将#{}解析为?

4、MyBatis 是否可以映射 Enum 枚举类?

答:MyBatis 可以映射枚举类,不单可以映射枚举类,MyBatis 可以映射任何对象到表的一列上。映射方式为自定义一个 TypeHandler,实现 TypeHandler 的 setParameter()和 getResult()接口方法。TypeHandler 有两个作用,一是完成从 javaType 至 jdbcType 的转换,二是完成 jdbcType 至 javaType 的转换,体现为 setParameter()和 getResult()两个方法,分别代表设置 sql 问号占位符参数和获取列查询结果。

实现自定义的typeHandler: 继承BaseTypeHandler<T> ---》 Mybatis就是依赖泛型参数<T>,获得泛型参数Class对象,再与反射获得的bean属性Class,进行一一对应的

除了上面的“智能”绑定外,我们还可以手动绑定TypeHandler。

<resultproperty="phone" column="phone"typeHandler="com.mybatis3.typehandlers.PhoneTypeHandler"/>

8、typehandler

mybatis默认提供的typehandler:

比如:

public TypeHandlerRegistry() {register(Boolean.class, new BooleanTypeHandler());register(boolean.class, new BooleanTypeHandler());register(JdbcType.BOOLEAN, new BooleanTypeHandler());register(JdbcType.BIT, new BooleanTypeHandler());register(JdbcType.VARCHAR, new StringTypeHandler());

自定义注册:

register(typeReference.getRawType(), typeHandler);

.getRawType()就是返回 泛化类型<T>

9、mybatis可以分页吗?如何?

Mybatis可以通过传递RowBounds对象,来进行数据库数据的分页操作,然而遗憾的是,该分页操作是对ResultSet结果集进行分页,也就是人们常说的逻辑分页,而非物理分页。

Rowbounds两个属性:offset + limit

offset就是从哪里开始读,最多读limit行

实现:

跳转到offset位置:

for (int i = 0; i < rowBounds.getOffset(); i++) {rs.next();}private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)throws SQLException {DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();skipRows(rsw.getResultSet(), rowBounds);while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);Object rowValue = getRowValue(rsw, discriminatedResultMap);storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());}}

10、mybatis如何返回在执行insert时生成的自增主键?

在Mybatis中,执行insert操作时,如果我们希望返回数据库生成的自增主键值,那么就需要使用到KeyGenerator对象。

。Mybatis是对JDBC的封装,其Jdbc3KeyGenerator类,就是使用下面的原理,来返回数据库生成的主键值的。

Class.forName("com.mysql.jdbc.Driver");

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "123");

conn.setAutoCommit(false);

PreparedStatement pstm = conn.prepareStatement("insert into students(name, email) values(?, ?)",

Statement.RETURN_GENERATED_KEYS);

pstm.setString(1, "name1");

pstm.setString(2, "email1");

pstm.addBatch();

pstm.setString(1, "name2");

pstm.setString(2, "email2");

pstm.addBatch();

pstm.executeBatch();

// 返回自增主键值

ResultSet rs = pstm.getGeneratedKeys();

while (rs.next()) {

Object value = rs.getObject(1);

System.out.println(value);

}

mit();

rs.close();

pstm.close();

conn.close();

output:

246

247

Mapper.Xml配置方式。

<insert id="insertStudents" useGeneratedKeys="true"keyProperty="studId"parameterType="Student">

主键赋值到keyproperty

11、如何批量插入List<student>?

<insert id="insertStudents" useGeneratedKeys="true" keyProperty="studId"parameterType="java.util.ArrayList">

INSERT INTO

STUDENTS(STUD_ID, NAME, EMAIL, DOB, PHONE)

VALUES

<foreachcollection="list" item="item" index="index" separator=",">

(#{item.studId},#{item.name},#{item.email},#{item.dob}, #{item.phone})

</foreach>

</insert>

此时返回主键id列表为null

11、Mybatis之foreach批量insert,返回主键id列表(修复Mybatis返回null的bug)

使用simpleExectuor/reuse可以返回

使用batch返回的是null

因为batch:如果传递的是List<Student>,那么,将包装为一个Map<String, Collection>对象

SimpleExecutor和ReuseExecutor可以正确返回foreach批量插入后的id列表的原理:

getParameters()方法,会再次处理参数类型,拆封map,获取map中的vaule 即collection对象

BatchResult又把Map<String, List<Student>>放到List中,于是,参数对象数据结构就变成了List<Map<String, List<Student>>>。

Java接口是否继承Object类?

https://dslztx.github.io/blog//04/22/Java%E6%8E%A5%E5%8F%A3%E6%98%AF%E5%90%A6%E7%BB%A7%E6%89%BFObject%E7%B1%BB/

看似是继承的,因为一个接口可以直接调用hashcode toString方法可以通过编译

但是如果接口继承了object类 接口就不能实例化

所以是,虚拟机制造了“继承的假象”。虚拟机会在顶层接口(没有父接口的接口)中自动定义一系列对应于Object类中“public”方法的虚方法,除非已经得到了显式定义,这点跟虚拟机会自动定义一个默认构造器类似。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。