MyBatis总结(笔面试题)
目录
Mybatis <https://blog.csdn.net/liyang_com/article/details/83756273#Mybatis>
1.谈谈MyBatis
<https://blog.csdn.net/liyang_com/article/details/83756273#1.%E8%B0%88%E8%B0%88MyBatis>
2.Mybatis分为三层
<https://blog.csdn.net/liyang_com/article/details/83756273#2.Mybatis%E5%88%86%E4%B8%BA%E4%B8%89%E5%B1%82>
3.Mybatis和jdbc的区别
<https://blog.csdn.net/liyang_com/article/details/83756273#3.Mybatis%E5%92%8Cjdbc%E7%9A%84%E5%8C%BA%E5%88%AB%C2%A0>
4.映射文件
<https://blog.csdn.net/liyang_com/article/details/83756273#4.%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6>
5.模糊查询:LIKE
<https://blog.csdn.net/liyang_com/article/details/83756273#5.%E6%A8%A1%E7%B3%8A%E6%9F%A5%E8%AF%A2%EF%BC%9ALIKE>
6.$和#的区别
<https://blog.csdn.net/liyang_com/article/details/83756273#6.%24%E5%92%8C%23%E7%9A%84%E5%8C%BA%E5%88%AB>
7.主键自增
<https://blog.csdn.net/liyang_com/article/details/83756273#7.%E4%B8%BB%E9%94%AE%E8%87%AA%E5%A2%9E>
8.API <https://blog.csdn.net/liyang_com/article/details/83756273#8.API>
9.SqlSession不是线程安全的
<https://blog.csdn.net/liyang_com/article/details/83756273#9.SqlSession%E4%B8%8D%E6%98%AF%E7%BA%BF%E7%A8%8B%E5%AE%89%E5%85%A8%E7%9A%84>
10.调用sqlSession.selectOne()还是SQLSession.selectList()是由mapper接口的返回值决定的
<https://blog.csdn.net/liyang_com/article/details/83756273#10.%E8%B0%83%E7%94%A8sqlSession.selectOne()%E8%BF%98%E6%98%AFSQLSession.selectList()%E6%98%AF%E7%94%B1mapper%E6%8E%A5%E5%8F%A3%E7%9A%84%E8%BF%94%E5%9B%9E%E5%80%BC%E5%86%B3%E5%AE%9A%E7%9A%84>
11.Mapper接口的参数:简单类型,pojo类型包装类型,Map,List集合等
<https://blog.csdn.net/liyang_com/article/details/83756273#11.Mapper%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%8F%82%E6%95%B0%EF%BC%9A%E7%AE%80%E5%8D%95%E7%B1%BB%E5%9E%8B%EF%BC%8Cpojo%E7%B1%BB%E5%9E%8B%E5%8C%85%E8%A3%85%E7%B1%BB%E5%9E%8B%EF%BC%8CMap%EF%BC%8CList%E9%9B%86%E5%90%88%E7%AD%89>
12.指定别名
<https://blog.csdn.net/liyang_com/article/details/83756273#12.%E6%8C%87%E5%AE%9A%E5%88%AB%E5%90%8D>
13.隐射文件的加载
<https://blog.csdn.net/liyang_com/article/details/83756273#13.%E9%9A%90%E5%B0%84%E6%96%87%E4%BB%B6%E7%9A%84%E5%8A%A0%E8%BD%BD>
14.输入参数
<https://blog.csdn.net/liyang_com/article/details/83756273#14.%E8%BE%93%E5%85%A5%E5%8F%82%E6%95%B0>
15.只写map的
<https://blog.csdn.net/liyang_com/article/details/83756273#15.%E5%8F%AA%E5%86%99map%E7%9A%84>
16.动态sql的编写
<https://blog.csdn.net/liyang_com/article/details/83756273#16.%E5%8A%A8%E6%80%81sql%E7%9A%84%E7%BC%96%E5%86%99>
17.缓存
<https://blog.csdn.net/liyang_com/article/details/83756273#17.%E7%BC%93%E5%AD%98>
18.Mybatis的编程步骤
<https://blog.csdn.net/liyang_com/article/details/83756273#18.Mybatis%E7%9A%84%E7%BC%96%E7%A8%8B%E6%AD%A5%E9%AA%A4>
19.主键自增问题
<https://blog.csdn.net/liyang_com/article/details/83756273#19.%E4%B8%BB%E9%94%AE%E8%87%AA%E5%A2%9E%E9%97%AE%E9%A2%98>
21.如何获取自动生成的(主)键值
<https://blog.csdn.net/liyang_com/article/details/83756273#21.%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90%E7%9A%84(%E4%B8%BB)%E9%94%AE%E5%80%BC>
22.使用MyBatis的mapper接口调用有哪些要求?
<https://blog.csdn.net/liyang_com/article/details/83756273#22.%E4%BD%BF%E7%94%A8MyBatis%E7%9A%84mapper%E6%8E%A5%E5%8F%A3%E8%B0%83%E7%94%A8%E6%9C%89%E5%93%AA%E4%BA%9B%E8%A6%81%E6%B1%82%EF%BC%9F>
23.Statement和PrepareStatement的区别
<https://blog.csdn.net/liyang_com/article/details/83756273#23.Statement%E5%92%8CPrepareStatement%E7%9A%84%E5%8C%BA%E5%88%AB>
<>Mybatis
<>1.谈谈MyBatis
Mybatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使得开发者只需要专注于SQL语句本身,而不用去关心注册驱动,创建connection等,Mybatis通过xml文件配置或者注解的方式将要执行的各种statement配置起来,并通过java对象和statement中的sql进行映射成最终执行的sql语句,最后由Mybatis框架执行sql并将结果映射成java对象并返回。
<>2.Mybatis分为三层
(1)API接口层:提供给外部使用的接口API
(2)数据处理层:负责具体的SQL
(3)基础支撑层:负责最基础的功能支撑,如连接管理,事务管理,配置加载和缓存处理
<>3.Mybatis和jdbc的区别
相比与jdbc,Mybatis具有以下优点
(1)数据库链接创建,释放频繁造成系统资源浪费会影响系统性能,使用数据库可以解决
解决:在核心配置文件SqlMapConfig.xml中配置数据链接池,使用数据链接池管理数据库链接
(2)Sql写在代码中不易于维护,修改需要变动java代码
在映射文件XXXMapper.xml文件中配置sql语句与Java代码分离
(3)向Sql语句传输参数麻烦,因为Sql语句的WHERE条件不一定,可能多也可能少,占位符需要和参数一一对应
Mybatis可以自动将Java对象映射到sql语句
(4)对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,将数据库记录封装成pojo对象解析更加方便
Mybatis可以自动将sql执行结果映射到Java对象
<>4.映射文件
* <mapper name="text">
*
* <select id="FindByID" paramenterType="int" resultType=
"com.guigu.User">
*
* select * from user where id=#{id}
*
* </select>
*
* </mapper>
namespace:名称空间 id:根据id执行sql parameterType:入参 resultType:出参 #{id} 接收的参数
<>5.模糊查询:LIKE
* <selectid="findByName2"
*
* parameterType="java.lang.String" resultType="com.gugiu.model.User">
*
* select * from user where name like '%${value}%'
*
* </select>
修改
* <update id="updateUserById" parameterType="com.gugiu.model.User">
*
* update user set name = #{name},age =#{age},address=#{address}
*
* where id =#{id}
*
* </update>
<>6.$和#的区别
(1)#把传入的参数当做字符串处理 $表示直接显示
(2)#很大程度防止Sql注入(语句拼接)
(3)能用#尽量用#
<>7.主键自增
<>8.API
(1)SqlSessionFactoryBuilder
通过加载MyBatisde 核心配置文件,创建SqlSessionFactory
(2)SqlSessionFactory
定义了openSession的不同重载方法
(3)sqlSession
定义了数据库的操作,增删改查
<>9.SqlSession不是线程安全的
<>10.调用sqlSession.selectOne()还是SQLSession.selectList()是由mapper接口的返回值决定的
* List<User> findUserByName(String name); selectList()
*
* User findUserByName(String name); selectOne()
<>11.Mapper接口的参数:简单类型,pojo类型包装类型,Map,List集合等
<>12.指定别名
单个文件
* <typeAliases>
*
* <typeAlias type="com.gugiu.model.User" alias="user"/>
*
* </typeAliases>
批量
* <typeAliases>
*
* <package name="com.guigu.model1"/>
*
* <package name="com.guigu.model2"/>
*
* </typeAliases>
<>13.隐射文件的加载
单个文件
* <mappers>
*
* <!—加载单个映射文件-->
*
* <mapper resource="com/guigu/mapper/UserMapper.xml"/>
* </mappers>
批量
* <mappers>
*
* <package name="com.guigu.mapper"/>
*
* </mappers>
<>14.输入参数
(1)简单类型
* <select id="findById" parameterType="int" resultType="user" >
*
* select * from User where id = #{id} ;
*
* </select>
(2)pojo类型
* <insert id="addUser" parameterType="com.guigu.model.User">
*
* <selectKey keyColumn="id" order="AFTER" resultType="int">
*
* SELECT LAST_INSERT_ID()
*
* </selectKey>
*
* INSERT INTO user (name,age,address)
*
* VALUE(#{name},#{age},#{address})
*
* </insert>
(3)pojo的包装类型
* <select id="findById" parameterType="com.guigu.model.UserVo" resultType=
"user">
*
* select * from User where id = #{user.id} ;
*
* </select>
(4)Map
* <insert id="addUserMap" parameterType="hashmap">
*
* INSERT INTO my_user(NAME,age,address) VALUE(#{name},#{age},#{address})
*
* </insert>
<>15.只写map的
* <selectid="findById" parameterType="int" resultMap="userMap">
*
* SELECT id ,name user_name FROM my_user WHERE id = #{id}
*
* </select>
<>16.动态sql的编写
(1)if
* <insert id="addUserVo" parameterType=
"com.guigu.mybatis.pojo.UserVo">
*
* <if test="user != null">
*
* insert into my_user (name,age,address)
*
* value(#{user.name},#{user.age},#{user.address})
*
* </if>
*
* </insert>
(2)where
* <select id="findByUserVo" parameterType="UserVo"resultType="User">
*
* select * from my_user
*
* <where>
*
* <iftest="user!= null">
*
* <if test="user.id != null and
user.id !='' ">
*
* and id = #{user.id}
*
* </if>
*
* <if test="user.name != null and
user.name !='' ">
*
* and name like
'%#{user.name}%'
*
* </if>
*
* </if>
*
* </where>
*
* </select>
(3)sql代码片段
* <sql id="find_user_byId">
*
* <if test="user.id != null and user.id !='' ">
*
* and id = #{user.id}
*
* </if>
*
* </sql>
*
* <sql id="find_user_byAge">
*
* <if test="user.age != null and user.age !='' ">
*
* and age = #{user.age}
*
* </if>
*
* </sql>
*
* <select id="findByUserVo" parameterType="UserVo" resultType=
"User">
*
* select * from my_user
*
* <where>
*
* <if test="user!= null">
*
* <include ref id="find_user_byId"></include>
*
* <include ref id="find_user_byAge"></include>
*
* </if>
*
* </where>
*
* </select>
(4)foreach
* <insert id="addUsers" parameterType="map">
*
* insert into my_user (name,age,address)
*
* <if test="users != null">
*
* values
*
* <foreach collection="users" item="user" separator=",">
*
* (#{user.name},#{user.age},#{user.address})
*
* </foreach>
*
* </if>
*
* </insert>
*
*
*
* <select id="findByIds" parameterType="map" resultType="User">
*
* <if test="userIds != null">
*
* select * from my_user
*
* <where>
*
* <foreach collection="userIds" item=
"userId" separator="or">
*
* id = #{userId}
*
* </foreach>
*
* </where>
*
* </if>
*
* </select>
<>17.缓存
(1)一级缓存(SqlSession级别)
MyBatis一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行
相同的sql语句,第一次执行后会将查询到的数据存储到缓存当中,第二次会从缓
存中进行查找,从而提高查询效率,当一个SqlSession结束之后,一级缓存也将不
存在,Mybatis默认开启一级缓存。
(2)二级缓存(Mapper级别)
二级缓存的作用域是mapper的同一个namespace,执行两次相同的SQL语句,第一次执行后会将查询到的数据存储到缓存当中,第二次会从缓存中进行查找,从而提高查询效率,默认不开启。
<>18.Mybatis的编程步骤
(0)创建SqlSessionFactoryBuilder
(1)通过SqlsesionFactoryBuilder创建sqlSessionFactory
(2)通过SqlSessionFactory创建sqlSession
(3)通过sqlSession执行数据库操作
(4)调用session.commit()提交事务
(5)调用session.close()关闭会话
* publicclass MyBatisUtil {
*
* privatestatic SqlSessionFactory factory = null;
*
* static {
*
* try {
*
* SqlSessionFactoryBuilder builder =
newSqlSessionFactoryBuilder();
*
* InputStream inputStream =
Resources.getResourceAsStream("MyBatisConfig.xml");
*
* //创建Session工厂
*
* factory = builder.build(inputStream);
*
* } catch (Exception e) {
*
* e.printStackTrace();
*
* }
*
* }
*
*
*
* publicstatic SqlSession getSqlSession(){
*
* //获得session会话
*
* return factory.openSession();
*
* }
*
* }
<>19.主键自增问题
20.实体类中的属性名和数据表中的列名不一致
(1)在sql语句中使用别名
(2)事先指定映射关系,这样Mybatis也能自动完成映射。Mybatis提供了resultMap标签
*
* <resultMap type="User" id="UserResultMap">
*
* <id column="id" property="id"/>
*
* <result column="user_name" property="userName"/>
*
* <result column="user_password" property="userPassword"/>
*
* </resultMap>
* Mybatis提供了一个全局属性mapUnderscoreToCamelCase来解决两者名字不一致的问题。
* <settings>
*
* <setting name="mapUnderscoreToCamelCase" value="true"/>
*
* </settings>
<>21.如何获取自动生成的(主)键值
解决思路:通过LAST_INSERT_ID()获取刚插入记录的自增主键值,在insert语句执行后,执行select
LAST_INSERT_ID()就可以获取自增主键。
* <insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
*
* <selectKey keyProperty="id" order="AFTER" resultType="int">
*
* select LAST_INSERT_ID()
*
* </selectKey>
*
* INSERT INTO USER(username,birthday,sex,address)
*
* VALUES(#{username},#{birthday},#{sex},#{address)
*
* </insert>
<>22.使用MyBatis的mapper接口调用有哪些要求?
(1)Mapper接口方法名和mapper.xml中定义的每个sql的id相同
(2)Mapper接口中输入的参数类型和mapper.xml中定义的每个sql的ParameterType相同
(3)Mapper接口中输出的参数类型和mapper.xml中定义的每个sql的resultType相同
(4)Mapper.xml文件中的namespace即是接口的类路径
<>23.Statement和PrepareStatement的区别
PreparedStatement:表示预编译的 SQL 语句的对象。
(1)PrepareStatement可以使用占位符,是预编译的,批处理比Statement效率高
(2)在对数据库只执行一次性存取的时侯,用 Statement 对象进行处理。
(3)PreparedStatement的第一次执行消耗是很高的. 它的性能体现在后面的重复执行