面试宝典总结一【Mybatis】

前言

根据各种方式学习总结,留此博客方便个人查阅。


目标

技术面广度以及深度提升,找到理想工作,离开对日开发。(有大佬收留可私信❀❀)

已更新面试技术总结

面试宝典总结二【Spring】


技术方向


必知

1.#{}和${}的区别是什么(面试会问)

#{}是预编译处理

eg:select * from user where reg_tms= #{reg_tms}   ※#{reg_tms} 是sql语句中的'?'号,调用PreparedStatement 的set 方法来赋值

${}是字符串替换

eg:order by ${user}  ※注意:${}不能防止sql注入

2. Mybatis 是如何进行分页的?

使用RowBounds对象进行分页,根据ResultSet返回的结果集进行分页,并不是物理内存分页

3. Mybatis 分页插件的原理是什么?(面试会问)

拦截器首先执行完重写sql语句,根据dialect进行详细的分页处理

源码分析

<dependency>
	<groupId>com.github.pagehelper</groupId>
	<artifactId>pagehelper</artifactId>
	<version>5.1.8</version>
</dependency>
    @RequestMapping("/listCategory")
    public String listCategory(Model m, @RequestParam(value = "start", defaultValue = "0") int start, @RequestParam(value = "size", defaultValue = "5") int size) throws Exception {
        PageHelper.startPage(start,size,"id desc");
        List<Category> cs=categoryServiceImpl.findAll();
        PageInfo<Category> page = new PageInfo<>(cs);
        m.addAttribute("page", page);
        return "listCategory";
    }
public class PageInterceptor implements Interceptor {
    // 重写sql语句,根据dialect进行详细的分页处理
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
	// 省略
    }
}

    /**
     * 开始分页
     *
     * @param pageNum  页码
     * @param pageSize 每页显示数量
     * @param orderBy  排序
     */
    public static <E> Page<E> startPage(int pageNum, int pageSize, String orderBy) {
        Page<E> page = startPage(pageNum, pageSize);
        page.setOrderBy(orderBy);
        return page;
    }

    /**
     * 开始分页
     *
     * @param pageNum      页码
     * @param pageSize     每页显示数量
     * @param count        是否进行count查询
     * @param reasonable   分页合理化,null时用默认配置
     * @param pageSizeZero true且pageSize=0时返回全部结果,false时分页,null时用默认配置
     */
    public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) {
        Page<E> page = new Page<E>(pageNum, pageSize, count);
        page.setReasonable(reasonable);
        page.setPageSizeZero(pageSizeZero);
        //当已经执行过orderBy的时候
        Page<E> oldPage = getLocalPage();
        if (oldPage != null && oldPage.isOrderByOnly()) {
            page.setOrderBy(oldPage.getOrderBy());
        }
        setLocalPage(page);
        return page;
    }

 4.Mybatis的映射形式 

<resultMap>标签

定义数据库列名和对象属性名之间的映射关系

<resultType>标签

将列的别名书写为对象属性名 

5.Mybatis 动态SQL(重点,面试会问)

 <choose>

判断参数

<where>
       <choose>
              <when test="isUpdate !=null ">
               AND user=#{user}
              </when>
       </choose>
</where>

<trim>

拼接关键字或去除多余字符

1.prefix

给sql语句拼接的前缀

2.suffix

给sql语句拼接的后缀

3.prefixOverrides

去除sql语句前面的关键字或字符

4.suffixOverrides

去除sql语句后面的关键字或字符

5.例子

<!-- 传入的state为空,title不为空 -->
<trim prefix="where" 
 prefixOverrides="and">
    <if test="state != null">
	  state = #{state}
	</if> 
    <if test="title != null">
	  and title = #{title}
	</if> 
</trim>

sql语句:where  state = ?

<where>

匹配条件

<set>

设置

<update >
    <set>
        <if test="user!=null">
           user =#{user},
       </if>
   </set>
</update>

具体作用

默认忽视逗号

<foreach>

循环

1.collection

返回类型

1_1.1 list

List<User> getUsers();
<select id="getUsers" resultType="User">
    select * from  user where user_id in
    <foreach collection="list" item="item" open="(" separator="," close=")" index="index">
         #{item}
    </foreach>
</select>
select * from  user where user_id in (?,?...?)

1_1.2 array

int delUsers(String[] arr);
<delete  id="delUsers">
    delete from  user where user_id in
    <foreach collection="array" item="item" open="(" separator="," close=")" index="index">
        #{item}
    </foreach>
</delete >
delete from  user where user_id in (?,?...?)

1_1.3 ids

List<User> getUsers();
<select id="getUsers" parameterType="java.util.Map" resultType="User">
     select * from  user where user_name = #{name} and user_id in
     <foreach collection="ids" item="item" open="(" separator="," close=")" index="index">
          #{item}
     </foreach>
</select>
  select * from  user where user_name = ? and user_id in (?,?...?)

1_1.4 对象

 int addUsers(User user); 
<insert id="addUsers" parameterType="User" >
    insert into tab_user (user_id,user_name) values
    <foreach collection="userId.split(',')" item="item" separator=",">
         (#{item},#{userName})
    </foreach>
 </insert>
 insert into tab_user (user_id,user_name) values (?,?);

2.index

索引(可选)

3.item

别名(必选)

4.open

开始符号(可选)

5.separator

分隔符(可选)

6.close

结束符号(可选)

<otherwise>

否则

<where>
    <choose>
           <when test="isUpdate !=null ">
               AND user=#{user}
           </when>
           <otherwise>
	           and user ='1'
           </otherwise>
    </choose>
</where> 

<bind>

绑定

<!--使用bind元素进行模糊查询-->
<select id="selectUserByBind" resultType="com.po.MyUser" parameterType= "com.po.MyUser">
    <!-- bind 中的 uname 是 com.po.MyUser 的属性名-->
    <bind name="paran_uname" value="'%' + uname + '%'"/>
        select * from user where uname like #{paran_uname}
</select>
 select * from user where uname like ('%?%')
<!-- 防止模糊查询sql注入 -->

 6.标签

<select>

1.id

唯一标识符,映射bean的方法名

List<Student> getAll();
<select id="getAll" ></select>

2.parameterType

参数类型

Student selectByPrimaryKey(Integer id);
<select id="selectByPrimaryKey" parameterType="java.lang.Integer"></select>

3.resultType

返回值类型

int  countUser();
<select id="countUser" resultType="int"></select>

4.resultMap

返回映射值

public class Student{
    private Integer id;
    private String name;
}
// mapper映射方法
Student selectByPrimaryKey(Integer id);
// 将返回的结果bean映射成键值对
<resultMap id="BaseResultMap" type="Student">
    <id column="id"  property="id" />
    <!-- column:映射student表里的字段name, jdbcType:映射student的name参数类型,property:映射Student.java里的参数name-->
    <result column="name" jdbcType="VARCHAR" property="name" />
</resultMap>

<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
</select>

<insert>

<insert id="insert" parameterType="Student"></insert>

<updae>

<update id="update" parameterType="Student"></update>

<delete>

<delete id="delete" parameterType="java.lang.Integer"></delete>

<sql>和<include>

Student selectByPrimaryKey(Integer id);  
  <sql id="Base_Column_List">
    id, name, sex, age, score
  </sql>

  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from student
    where id = #{id,jdbcType=INTEGER}
  </select>

<selectKey>

int insert(Student record);  
   <insert id="insert" parameterType="Student">
    <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
      SELECT LAST_INSERT_ID()
    </selectKey>
    insert into student (name,)
    values (#{name,jdbcType=VARCHAR})
  </insert>

<constructor>

构造方法

public class Student{
    private Integer id;
    private String name;
    get/set省略
    public Student(Integer id, String name, User user) {
	super();
	this.id = id;
	this.name = name;
	this.user = user;
   } 
}
List<Student> findStudentAll();
<resultMap id="BaseResultMap" type="Student">
   <constructor>
       <idArg column="id" javaType="Integer"/>
       <arg column="name" javaType="String"/>
       <!--  typeHandler:映射的bean -->
       <arg column="user" javaType="User" typeHandler="User"/>
   </constructor>
</resultMap>

<select id="findStudentAll" resultMap="BaseResultMap" >
        select * from student;
</select>

<association>

一对一关联查询

public class Person {
    private Integer id;
    private String name;
    private User user;

    // 省略setter和getter方法
}

public class User {
    private Integer id;
    private String code;

    // 省略setter和getter方法
}

Person selectCodeById(Integer id);
<select id="selectCodeById" parameterType="Integer" resultType= "User>
        select * from user where id=#{id}
</select>

<resultMap type="Person" id="BaseResultMap">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <!-- 一对一级联查询-->
        <association property="user" column="user_id" javaType="User"
        select="selectCodeByld"/>
</resultMap>
<select id="selectPersonById" parameterType="Integer" resultMap=
    "BaseResultMap">
        select * from person where id=#{id}
</select>

<collection>

一对多关联查询

public class Person {
    private Integer id;
    private String name;
    private List<User> users;

    // 省略setter和getter方法
}

public class User {
    private Integer id;
    private String code;

    // 省略setter和getter方法
}
Person selectCodeById(Integer id);
<select id="selectCodeById" parameterType="Integer" resultType= "User>
        select * from user where id=#{id}
</select>
<resultMap type="Person" id="BaseResultMap">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <!-- 一对多级联查询-->
        <collection property="users" column="users" ofType="User"
        select="selectCodeByld"/>
        <!-- <collection property="users" ofType="User">
            <id property="id" column="id" />
            <result property="code" column="code" />
        </collection> -->
</resultMap>
<select id="selectPersonById" parameterType="Integer" resultMap=
    "BaseResultMap">
        select * from person where id=#{id}
</select>

<discriminator>

鉴别器/分类器:分别同样的子类,返回不同信息

数据库表字段
id int(11) NO PRI auto_increment
name varchar(50) YES  
sex varchar(2) YES  
age varchar(10) YES  
type varchar(50) YES  

id | name | sex | age | type
0 | tom | 男 | 20 | 1
1 | kit | 女 |18 | 2
public class Person {
    private Integer id;
    private String name;
    private String sex;
    private String age;

    // 省略setter和getter方法
}

public class Student extends Person{
    private Integer id;
    private String name;
    private String age;

    // 省略setter和getter方法
}

public class User extends Person{
    private Integer id;
    private String name;
    private String sex;

    // 省略setter和getter方法
}

Person selectPersonById(Integer id);
<resultMap type="Person" id="BaseResultMap">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="sex" column="sex"/>
        <result property="age" column="age"/>
        <!-- 根据type判断返回什么对象 -->
        <discriminator javaType="int" column="type">
             <case value="1" resultType="Student">
                <id column="id" property="id"/>
                <result column="name" property="name"/>
                <result column="age" property="age"/>
            </case>
            <case value="2" resultType="User">
                <id column="id" property="id"/>
                <result column="name" property="name"/>
                <result column="sex" property="sex"/>
            </case>
        </discriminator>
</resultMap>
<select id="selectPersonById" parameterType="Integer" resultMap="BaseResultMap">
        select * from person where id=#{id}
</select>
# 结果
select * from person WHERE `id` = ?; 
Student{id='0',name='tom',age='20'}
select * from person WHERE `id` = ?; 
User{id='1',name='kit',sex='女'}

7.Mybatis延迟加载原理(面试会问)

package org.apache.ibatis.executor.loader.cglib;
public class CglibProxyFactory implements ProxyFactory {
     // 创建代理对象
     crateProxy()
    // 代理对象执行
    invoke()
    // 主要执行逻辑 ,通过synchronized 判断mybatis的配置为true
    // 延迟加载数量大于0
    if (lazyLoader.size() > 0 && !FINALIZE_METHOD.equals(methodName)) {
      // aggressive一对一关联查询进入
      if (aggressive || lazyLoadTriggerMethods.contains(methodName)) {
        // 对象返回
        lazyLoader.loadAll();
      } else if (PropertyNamer.isSetter(methodName)) {
        // set 标签不需要执行延迟加载
        final String property = PropertyNamer.methodToProperty(methodName);
        lazyLoader.remove(property);
      } else if (PropertyNamer.isGetter(methodName)) {
        final String property = PropertyNamer.methodToProperty(methodName);
        if (lazyLoader.hasLoader(property)) {
          lazyLoader.load(property);
        }
      }
    }
}

public class Person {
    private List<User> users;
    // 省略setter和getter方法
}
public class User {
}

 使用CGLib代理模式,创建代理对象,进入intercept()方法,当匹配方法名一致,Person.getUsers()返回null,把事先保存的sql关联查询出User对象,在调用Person.setUsers(users),最后返回结果。

8.基础配置(面试会问)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 配置全局属性 -->
    <settings>
        <!--允许返回多个结果集-->
        <setting name="multipleResultSetsEnabled" value="true"></setting>
        <!-- 使用jdbc的getGeneratedKeys获取数据库自增主键值 -->
        <setting name="useGeneratedKeys" value="true" />
        <!-- 使用列别名替换列名 默认:true -->
        <setting name="useColumnLabel" value="true" />
        <!-- 开启驼峰命名转换:Table{create_time} -> Entity{createTime} -->
        <setting name="mapUnderscoreToCamelCase" value="true" />
        <!--二级缓存开关-->
        <setting name="cacheEnabled" value="true"></setting>
        <!--允许返回多个结果集-->
        <setting name="multipleResultSetsEnabled" value="true"></setting>
        <!--日志-->
        <setting name="logImpl" value="LOG4J"></setting>
        <!-- 延迟加载总开关( 查询时,关闭关联对象即时加载以提高性能) -->
        <setting name="lazyLoadingEnabled" value="false"/>
        <!-- 侵入懒加载,设置为false则按需加载,否则会全部加载 -->
        <setting name="aggressiveLazyLoading" value="false"/>
        <!--设置一个时限,以决定让驱动器等待数据库回应的多长时间为超时-->
        <setting name="defaultStatementTimeout" value="25000" />
    </settings>
    <!-- mybatis分页插件 -->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>
</configuration>

扩展 

关于mybatis+maven基本知识掌握总结

maven中spring+springmvc+mybatis整合详细配置

SpringBoot+Mybatis+Redis基础配置

Vue+Mysql+SpringBoot简单增删改查

9.Executor执行器(面试会问)

SimpleExecutor

每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象

ReuseExecutor

执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map 

BatchExecutor

完成批处理 

10.Mybatis一级和二级缓存 

一级缓存

使用session,默认打开一级缓存且不能关闭。

一级缓存是SqlSession级别的数据,作用域是SqlSession范围的。一个查询产生的一个SqlSession。在同一个SqlSession中执行两次相同的SQL语句时,第一次执行完的数据库中查询的数据斜倒缓冲中,第二次查询是从缓存中获取数据,不再去底层数据库查询,从而提高性能。

注意:为了避免脏数据的出现。(在执行了增删改操作后,mybatis会清空sqlsession中的一级缓存)

二级缓存

默认不打开二级缓存,要手动开启二级缓存 

二级缓存是mapper级别的缓存,在多个SqlSession使用一个mapper时,在对数据库查询操作时,利用二级缓存来提高查询性能。

不同的SqlSession两次执行相同的namespace下的SQL语句,切向SQL中传递的参数也相同 ,第二次执行的数据是在缓存中获取。

11.Mybatis是什么(面试会问)

Mybatis是一个半ORM(对象关系映射)框架 

a.封装JDBC,开发人员不需要关心sql语句,原生的statement不需要程序员管控

b. 使用XML或注解映射Dao,将POJO映射成数据库中的记录

总结:可以自定义sql、存储过程和高级映射的持久层框架

12.mapper创建原理 (面试会问)

JDK动态代理+工厂模式

创建一个SqlSessionFactory对象读取mybatis相关配置,然后使用session对象调用getMapper反射到对应的bean和sql。getMapper利用jdk代理模式返回任何对象,遇到特殊的方法名进入CRUD装配调用。

源码解析 

public void save(User u) throws IOException {
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
        SqlSession session = factory.openSession();
        // 传入要解析的bean,此bean会自动映射xml文件或注解
        UserMapper mapper = session.getMapper(UserMapper.class);
        mapper.save(u);
        session.commit();
        session.close();
    }
package org.apache.ibatis.session.defaults

DefaultSqlSession.java

   @Override
  public <T> T getMapper(Class<T> type) {
    return configuration.<T>getMapper(type, this);
  }
package org.apache.ibatis.session;

Configuration.java

   /**
   * type:类型
   * sqlsession:主要配置,连接jdbc的用户和密码,外部扩展
   */
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }
package org.apache.ibatis.binding;

MapperRegistry.java

  @SuppressWarnings("unchecked")
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    // 最终的读取出来的映射数据类型,statement的各种设置
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      // jdk动态代理:生成一个实体类
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }
package org.apache.ibatis.binding;
MapperProxyFactory.java

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    // 检查public和非空判断,反射执行,深拷贝了Proxy对象 ,mapperProxy被代理对象
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    // 构造一个MapperProxy对象
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }
package org.apache.ibatis.binding;
MapperProxy.java
// jdk动态代理必须实现InvocationHandler
public class MapperProxy<T> implements InvocationHandler, Serializable {

  private static final long serialVersionUID = -6424540398559729838L;
  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache;

  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }

// 然后重写此方法
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
     // 任何方法名都可以代理生成对象
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
   // 缓存方法
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    // 判断sql执行类型
    return mapperMethod.execute(sqlSession, args);
  }

  private MapperMethod cachedMapperMethod(Method method) {
    return methodCache.computeIfAbsent(method, k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
  }

  private Object invokeDefaultMethod(Object proxy, Method method, Object[] args)
      throws Throwable {
    final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class
        .getDeclaredConstructor(Class.class, int.class);
    if (!constructor.isAccessible()) {
      constructor.setAccessible(true);
    }
    final Class<?> declaringClass = method.getDeclaringClass();
    return constructor
        .newInstance(declaringClass,
            MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
                | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC)
        .unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
  }

  /**
   * Backport of java.lang.reflect.Method#isDefault()
   */
  private boolean isDefaultMethod(Method method) {
    return (method.getModifiers()
        & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC
        && method.getDeclaringClass().isInterface();
  }
}


 public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      case INSERT: {
    	Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
          if (method.returnsOptional() &&
              (result == null || !method.getReturnType().equals(result.getClass()))) {
            result = Optional.ofNullable(result);
          }
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName()
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }

13.Mybatis优点/缺点 

优点

减少重复的轮子

兼容主流数据库

扩展性高

缺点

更换数据库成本很高

SQL语句要求很高 

14.Mybatis三大核心对象以及作用域(面试会问)

三大对象:

1、SqlSessionFactoryBuilder:负责构建SqlSessionFactory,并且提供了多个build()方法的重载

2、SqlSessionFactory:创建SqlSession实例的工厂

3、SqlSession:用于执行持久化操作的对象

生命周期以及作用域:

          SqlSessionFactoryBuilder:用过即丢,创建SqlSessionFactory对象后该方法就不存在,所以该方法的范围是在方法体内部

          SqlSessionFactory:整个运行过程中都需要,作用域Application

   SqlSession:在每次访问数据库时都需要它,作用域:request作用域或者方法体作用域

15.扫描package方式(面试会问)

第一种方式

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <mappers>
        <!-- 调用dao层 -->
        <mapper resource="org/lisonglin/mapper/StudentMapper.xml"/>
    </mappers>
</configuration>

第二种方式

application.properties

#SQL语句映射文件
#mybatis.mapper-locaitons= classpath*:com/example/mapper/*.xml
mybatis.mapper-locations=classpath*:org/lanqiao/mapper/*.xml
# 类的别名的包
mybatis.type-aliases-package=org.lanqiao.model

16.SqlSession相关API(面试会问)

  • SqlSession是一个面向用户的接口,接口中定义了操作数据库的方法(selectOne、selectList、insert、update、delete)。
  • SqlSession的实现类是线程不安全的,所以SqlSession不能定义成局部变量来使用,最佳的使用场合是在一个方法体内(即:作为一个局部变量来使用)。

SqlSession实例,包括了所有执行语句、提交或回滚事务和获取映射器实例的方法。

    <T> T selectOne(String statement, Object parameter);
    <E> List<E> selectList(String statement, Object parameter);
    int insert(String statement, Object parameter);
    int update(String statement, Object parameter);
    int delete(String statement, Object parameter);

    void commit()
    void rollback()

17.SqlSessionFactoryBuilder相关API(面试会问)

SqlSession工厂构造器SqlSessionFactoryBuilder

常用API: SqlSessionFactory build(InputStream inputStream)

通过加载mybatis的核心文件的输入流的形式构建一个SqlSessionFactory对象.

 InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
 SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);

18.SqlSessionFactory相关API(面试会问)

SqlSessionFactory 有多个方法可以创建SqlSession实例。

方法 解释
openSession() 会默认开启一个事务,但事务不会自动提交。需要手动提交改事务。
openSession(boolean autoCommit) 参数为是否自动提交,设置为true,就不再需要手动提交事务。
 SqlSession sqlSession = build.openSession();
 StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

 19.事务机制和实际操作(面试会问)

事务管理

①使用JDBC的事务管理机制

利用java.sql.Connection对象完成对事务的提交commit()、回滚rollback()和关闭close()等操作。

②使用managed的事务管理机制

对于这种机制,mybatis自身不会去实现事务管理,而是让容器如WebLogic、JBOSS等来实现事务的管理。

@Service
public class StudentService{

    @Autowired
    StudentDao studentDao;

    @Transactional(isolation = Isolation.READ_COMMITTED, readOnly = false, rollbackFor = Exception.class)
    public int insert(Student record,String hobbys){
        return studentDao.insertStudent(record,hobbys);
    };

}

猜你喜欢

转载自blog.csdn.net/qq_41520636/article/details/113764366
今日推荐