ThreadLocal
- ThreadLocal:线程容器,可以给线程绑定一个Object内容。 只要线程不变,任何时刻,线程都绑着一个Object对象,可以往里面放东西。一旦改变线程,就无法取出。
- 匿名内部类在引用参数时,要么是final,要么就是全局的,怕被改变对象地址。
public static void main(String[] args) {
final ThreadLocal<String> tl = new ThreadLocal<String>();
tl.set("测试");
new Thread() {
public void run() {
String result = tl.get();
System.out.println(result);//结果为null
}
}.start();
}
OpenSessionView
最早是由Spring框架提出的,整合Hibernate框架使用。 原理是利用ThreadLocal能绑定对象,且从servlet到service到Mybatis都是一个线程。编写Mybatis工具类,简化service代码。
-
fifter过滤器
- 使用注解配置
@WebFilter("/*")
- 在web.xml中配置
- 使用注解配置
<filter>
<filter-name>opensession</filter-name>
<filter-class>filter.OpenSessionInView</filter-class>
</filter>
<filter-mapping>
<filter-name>opensession</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
在过滤器中设置session
@Override
public void doFilter(ServletRequest servletrequest, ServletResponse servletresponse, FilterChain filterchain)
throws IOException, ServletException {
try {
filterchain.doFilter(servletrequest, servletresponse);
session.commit();
} catch (Exception e) {
session.rollback();
e.printStackTrace();
}finally{
MyBatisUtil.closeSession();
}
}
-
MybatisUtil.java
public class MyBatisUtil {
//factory实例化的过程是一个比较耗费性能的过程.
//保证有且只有一个factory
private static SqlSessionFactory factory;
private static ThreadLocal<SqlSession> tl = new ThreadLocal<>();
static{
try {
InputStream is = Resources.getResourceAsStream("mybatis.xml");
factory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 获取SqlSession的方法
*/
public static SqlSession getSession(){
SqlSession session = tl.get();
if(session==null){
tl.set(factory.openSession());
}
return tl.get();
}
public static void closeSession(){
SqlSession session = tl.get();
if(session!=null){
session.close();
}
tl.set(null);
}
}
如此一来,service中的代码大量减少 例如在Log类中插入的service
@Override
public int ins(Log log) {
SqlSession session = MyBatisUtil.getSession();
LogMapper mapper = session.getMapper(LogMapper.class);
return mapper.ins(log);
}
缓存
- 缓存的意义:应用程序和数据库交互的过程是一个相对比较耗时的过程,缓存可以减少应用程序对数据库的访问,提升系统效率。
- 在Mybatis默认Sqlsession缓存开。
(1) 即同一个SQLSession对象调用同一个select时,只有第一次访问数据库,第一次之后把查询结果缓存到SQLSession中。
(2)缓存的是statement对象。在Mybatis中,一个select对象一个statement对象。 - 缓存流程
- 先去缓存区查看是否有statement,返回结果
- 如果没有缓存statement对象,去数据库获取数据
- 数据库返回查询结果
- 把查询结果放到对应的缓存区中
- SQLSessionFactory缓存(二级缓存):当数据被频繁使用,很少被修改
有效范围:同一个factory中,哪一个SQLSession都可以获取- 使用步骤:
在mapper.xml中添加,如果不写readOnly属性,需要把实体类序列化
<cache readOnly="true"></cache>
当SQLSession对象关闭或提交时,会把SQLSession缓存对象刷(flush)到SQLSessionFactory缓存区中。
- 使用步骤:
在mapper.xml中添加,如果不写readOnly属性,需要把实体类序列化
多表查询
-
实现方式
- 业务装配:对两个表编写表单查询语句,在业务(Service)把查询结果进行关联。
- Auto Mapping:利用该特性,在实现两表联合查询时通过别名完成映射。
- resultMap:使用Mybatis的resultMap标签
-
多表查询时,类中包含另一个类的对象的分类
- 单个对象
- 集合对象
-
resultMap标签
- 写在mapper.xml中,由程序员控制SQL查询结果与实体类的映射关系,默认使用Auto Mapping特性。
- 使用resultMap标签时,select标签是使用resultMap 而不使用resultType属性。
例如:搜索People类,其中实体类中的id属性为id1,name属性为name1
<select id="selAll" resultMap="mymap">
select * from people
</select>
<resultMap type="people" id="mymap">
<!-- 主键使用id标签配置映射关系 -->
<!--
column:映射到数据库中的属性名
property:实体类中的属性名
-->
<id column="id" property="id1"/>
<!-- 其他列使用result标签配置映射关系 -->
<result column="name" property="name1"/>
</resultMap>
-
resultMap实现关联单个对象(N+1)
- N+1查询方式:先查询出某个表的全部信息,再根据这个表的信息查询另一个表的信息。
- 与业务装配的区别:以前在service写的代码,有Mybatis完成装配
例:student类中包含teacher对象,查询学生对应的老师
StudentMapper
<resultMap type="student" id="stuMap">
<result column="tid" property="tid"/>
<!-- 如果关联一个对象 -->
<association property="teacher" select="com.bjsxt.mapper.TeacherMapper.selById" column="tid"></association>
</resultMap>
<select id="selAll" resultMap="stuMap">
select * from student
</select>
<select id="selAll1" resultMap="stuMap1">
select * from student
</select>
TeacherMapper
<select id="selById" resultType="teacher" parameterType="int">
select * from teacher where id=#{0}
</select>
其中:
association:装配一个对象时使用该标签
property:对象在类中的属性名
select:通过哪个查询查询出该对象的信息
column:把当前表的哪一列的值作为参数传递给另一个查询
- 注意:使用N+1方式时,列名和属性名一致可以不配置,使用AutoMapping特性。但是Mybatis默认只会给列配置一次。如上例中,tid作为值传递给第二个查询,则不会给它配置id属性,需要手动配置。
-
resultMap加载集合对象
N+1
使用collection标签
例如:查询老师的所有学生,一个老师对应多个学生
TeacherMapper
<resultMap type="teacher" id="mymap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<collection property="list" select="com.bjsxt.mapper.StudentMapper.selByTid" column="id">
</collection>
</resultMap>
<select id="selAll" resultMap="mymap">
select * from teacher
</select>
StudentMapper
<select id="selByTid" parameterType="int" resultType="student">
select * from student where tid=#{0}
</select>
多表联合查询方式
Mybatis可以通过主键判断对象是否被加载过,所以不会重复创建Teacher
<resultMap type="teacher" id="mymap1">
<id column="tid" property="id"/>
<result column="tname" property="name"/>
<collection property="list" ofType="student" >
<id column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="age" property="age"/>
<result column="tid" property="tid"/>
</collection>
</resultMap>
<select id="selAll1" resultMap="mymap1">
select t.id tid,t.name tname,s.id sid,s.name sname,age,tid from teacher t LEFT JOIN student s on t.id=s.tid;
</select>
-
AutoMapping结合别名实现多表查询
这种方式不能使用N+1,只能使用多表联合。
要求:查询出的列名和属性名一致。
注意:.在SQL是关键字,需要在用反单引号包住别名。
<select id="selAll" resultType="student">
select t.id `teacher.id`,t.name `teacher.name`,s.id id,s.name name,age,tid
from student s LEFT JOIN teacher t on t.id=s.tid
</select>
注解
- 目的:简化mapper.xml文件。
- 原因:如果涉及动态SQL,仍然使用mapper.xml。
- 注意:
(1)mapper.xml与注解可以共存 (2)使用注解时,mapper.xml中的mappers标签中要么使用package,或者class标签。
<mapper class="mapper.XXXMapper">
- 使用:直接在接口方法上写
格式为:@Select/Insert/Update/Delete("SQL语句")
@Select("select * from student")
List<Student> selAll();
- 若要使用ResultMap则比较麻烦,需要在SQL语句上方再加一句注解。
例:N+1查询集合对象
@Resuls(value={
@Result(id=true,property="id" column="id"),
@Result(porperty="name" column="name"),
@Result(porterty="list" column="id",many=@Many(namespace+方法名)
})
运行原理
运行过程中涉及的类
- Resource:Mybatis中IO流的工具类,用于加载配置文件
- SQLSessionFactoryBuilder():构造器,创建SQLSession接口的实现类
- XMLConfigBuilder:Mybatis全局配置文件构造器类,负责读取流内容并转换为Java代码。
- Configuration:封存了全局配置文件内容
- DefaultSessionFactory:是SQLSessionFactory的实现类
- Transaction事务类:每一个SQLSession会带有一个Transaction对象
- TransactionFactory:事务工厂,负责生产Transaction
- Executor:Mybatis执行器,负责执行SQL命令,相当于JDBC的statement对象,默认的执行器SimpleExecutor,批量操作是BatchExecutor
- DefaultSqlSession:SqlSession的实现类
- ExeceptionFactory:Mybatis异常工厂