mybaits 的配置文件
<?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>
<properties resource="db.properties"/>
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
<setting name="cacheEnabled" value="true"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<typeAliases>
<package name="note.entity"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="note.dao"/>
</mappers>
</configuration>
数据库的 properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/stage2?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=123
log4j 的配置 properties
log4j.rootLogger=OFF
log4j.logger.note.dao=DEBUG,CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%p %c{1}:%L - %m%n
log4j.appender.FILE=org.apache.log4j.DailyRollingFileAppender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%p] %m [%t] %c [%l]%n
log4j.appender.FILE.File=file.log
生成 sqlssesion 的工具类
package note.util;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class SqlSessionUtil {
static SqlSessionFactory sqlSessionFactory= null;
public static SqlSession getSqlSession(){
if (sqlSessionFactory == null) {
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream("mybatisConfig.xml");
} catch (IOException e) {
e.printStackTrace();
}
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
return sqlSessionFactory.openSession(false);
}
}
entity 实体类
package note.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Class {
private Integer id;
private String name;
private List<Teacher> teachers;
}
package note.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ClassTeacherMap {
private Integer id;
private Integer avrScore;
private Class aClass;
private Teacher teacher;
}
package note.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dep {
private Integer id;
private String name;
private List<Emp> empList;
}
package note.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
private Integer id;
private String name;
private Dep dep;
}
package note.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Teacher {
private Integer id;
private String name;
private List<Class> classes;
}
dao 接口
package note.dao;
import note.entity.Class;
public interface ClassDao {
Class selectClassById(int cid);
Class selectClassById2(int cid);
}
package note.dao;
import note.entity.ClassTeacherMap;
public interface ClassTeacherMapDao {
ClassTeacherMap selectClaTeaById(int id);
ClassTeacherMap selectClaTeaById2(int id);
}
package note.dao;
import note.entity.Dep;
public interface DepDao {
Dep selectDepById(int id);
Dep selectDepById2(int id);
}
package note.dao;
import note.entity.Emp;
public interface EmpDao {
Emp selectEmpById(int id);
Emp selectEmpById2(int id);
}
接口的 mapper
<?xml version="1.0" encoding="UTF-8" ?>
<!--导入第三方约束文件,表示本文件在准守xml语法的同时还要准守这里的mybatis-3-mapper.dtd(mybatis的映射文件)文件中制定的语法-->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="note.dao.ClassDao"><!--命名空间,一般为映射文件实体类的全限定名-->
<!--中间表连表查询-->
<select id="selectClassById" resultMap="classMap">
select class_teacher_map.id id,
class_teacher_map.cid cid, class_teacher_map.tid tid, avr_score, class.name cname, teacher.name tname from class_teacher_map, class, teacher where class_teacher_map.cid = class.id and class_teacher_map.tid = teacher.id and class.id = #{id}; </select>
<resultMap id="classMap" type="Class">
<id property="id" column="cid"/>
<result property="name" column="cname"/>
<collection property="teachers" ofType="Teacher">
<id property="id" column="tid"/>
<result property="name" column="tname"/>
</collection> </resultMap>
<!--中间表分步查询-->
<select id="selectClassById2" resultMap="classMap2">
select *
from class where id = #{id} </select>
<resultMap id="classMap2" type="class">
<id property="id" column="id"/>
<result property="name" column="name"/>
<collection property="teachers" column="id" ofType="teacher" select="selectTeacherByCid"/>
</resultMap> <select id="selectTeacherByCid" resultType="teacher">
select tid id, name
from class_teacher_map,teacher where class_teacher_map.tid = teacher.id and cid = #{id} </select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!--导入第三方约束文件,表示本文件在准守xml语法的同时还要准守这里的mybatis-3-mapper.dtd(mybatis的映射文件)文件中制定的语法-->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="note.dao.ClassTeacherMapDao"><!--命名空间,一般为映射文件实体类的全限定名-->
<!--多对多查询方式,连表查询一步-->
<select id="selectClaTeaById" resultMap="classTeacherMapMap">
select class_teacher_map.id id, class_teacher_map.cid cid, class_teacher_map.tid tid, class_teacher_map.avr_score avr_score, class.name cname, teacher.name tname
from class_teacher_map, class, teacher where class_teacher_map.cid = class.id and class_teacher_map.tid = teacher.id and class_teacher_map.id = #{id}; </select>
<resultMap id="classTeacherMapMap" type="ClassTeacherMap">
<id column="id" property="id"/>
<result column="avr_score" property="avrScore"/>
<association property="aClass" javaType="Class">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
</association>
<association property="teacher" javaType="Teacher">
<id column="tid" property="id"/>
<result column="tname" property="name"/>
</association>
</resultMap>
<!--分步查询-->
<select id="selectClaTeaById2" resultMap="classTeacherMapMap2">
select *
from class_teacher_map where class_teacher_map.id = #{id}; </select>
<resultMap id="classTeacherMapMap2" type="ClassTeacherMap">
<id column="id" property="id"/>
<result column="avr_score" property="avrScore"/>
<association property="aClass" javaType="Class" select="selectClassByCid" column="cid"/>
<association property="teacher" javaType="Teacher" select="selectTeacherByTid" column="tid"/>
</resultMap>
<select id="selectClassByCid" resultType="Class">
select *
from class where id = #{cid}; </select>
<select id="selectTeacherByTid" resultType="Teacher">
select *
from teacher where id = #{tid}; </select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!--导入第三方约束文件,表示本文件在准守xml语法的同时还要准守这里的mybatis-3-mapper.dtd(mybatis的映射文件)文件中制定的语法-->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="note.dao.DepDao"><!--命名空间,一般为映射文件实体类的全限定名-->
<!--一对多查询(使用连接一步查询)-->
<select id="selectDepById" resultMap="depMap">
select dep.id, dep.name, emp.id eid, emp.name ename
from dep, emp where dep.id = emp.did and dep.id = 1 </select>
<resultMap id="depMap" type="Dep">
<id property="id" column="id"/>
<result property="name" column="name"/>
<collection property="empList" ofType="Emp">
<id property="id" column="eid"/>
<result property="name" column="ename"/>
</collection>
</resultMap>
<!--一对多查询(分步查询)-->
<select id="selectDepById2" resultMap="depMap2">
select *
from dep where id = #{id} </select>
<resultMap id="depMap2" type="Dep">
<id property="id" column="id"/>
<result property="name" column="name"/>
<collection property="empList" column="id" ofType="Emp" select="selectEmpById"/>
</resultMap>
<select id="selectEmpById" resultType="Emp">
select *
from emp where did = #{id} </select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!--导入第三方约束文件,表示本文件在准守xml语法的同时还要准守这里的mybatis-3-mapper.dtd(mybatis的映射文件)文件中制定的语法-->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="note.dao.EmpDao"><!--命名空间,一般为映射文件实体类的全限定名-->
<!-- 加上cache标签之后表示当前mapper中产生的数据是"可以"被放到二级缓存中 -->
<cache readOnly="true"/>
<!--多对一查询,连接一步查询-->
<select id="selectEmpById" resultMap="empMap">
select emp.id,emp.name,dep.id did,dep.name dname
from emp, dep where emp.did = dep.id and emp.id = #{id}; </select>
<resultMap id="empMap" type="Emp">
<id property="id" column="id"/>
<result property="name" column="name"/>
<association property="dep" javaType="Dep">
<id property="id" column="did"/>
<result property="name" column="dname"/>
</association>
</resultMap>
<!--多对一查询,分步查询-->
<select id="selectEmpById2" resultMap="empMap2">
select *
from emp where id = #{id}; </select>
<resultMap id="empMap2" type="Emp">
<id property="id" column="id"/>
<result property="name" column="name"/>
<association property="dep" column="did" javaType="Dep" select="selectDepById"/>
</resultMap>
<select id="selectDepById" resultType="Dep">
select *
from dep where id = #{did}; </select>
</mapper>
测试类
package note.dao;
import note.entity.Class;
import note.util.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class ClassDaoTest {
SqlSession sqlSession = null;
ClassDao mapper = null;
@Before
public void setUp() {
sqlSession = SqlSessionUtil.getSqlSession();
mapper = sqlSession.getMapper(ClassDao.class);
}
@After
public void tearDown() {
if (sqlSession != null) {
sqlSession.close();
}
}
@Test
public void selectClassById() {
Class aClass = mapper.selectClassById(1);
System.out.println(aClass);
}
@Test
public void selectClassById2() {
Class aClass = mapper.selectClassById2(1);
System.out.println(aClass);
}
}
package note.dao;
import note.entity.ClassTeacherMap;
import note.util.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class ClassTeacherDaoTest {
SqlSession sqlSession = null;
ClassTeacherMapDao classTeacherMapDao = null;
@Before
public void setUp() {
sqlSession = SqlSessionUtil.getSqlSession();
classTeacherMapDao = sqlSession.getMapper(ClassTeacherMapDao.class);
}
@After
public void tearDown() {
if (sqlSession != null) {
sqlSession.close();
}
}
@Test
public void selectClaTeaById() {
ClassTeacherMap class_teacher = classTeacherMapDao.selectClaTeaById(5);
System.out.println(class_teacher);
}
@Test
public void selectClaTeaById2() {
ClassTeacherMap class_teacher = classTeacherMapDao.selectClaTeaById2(5);
System.out.println(class_teacher);
}
}
package note.dao;
import note.entity.Dep;
import note.util.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class DepDaoTest {
SqlSession sqlSession = null;
DepDao mapper = null;
@Before
public void setUp() {
sqlSession = SqlSessionUtil.getSqlSession();
mapper = sqlSession.getMapper(DepDao.class);
}
@After
public void tearDown() {
if (sqlSession != null) {
sqlSession.close();
}
}
@Test
public void selectDepById() {
Dep dep = mapper.selectDepById(1);
System.out.println(dep);
}
@Test
public void selectDepById2() {
Dep dep = mapper.selectDepById2(1);
System.out.println(dep);
}
}
package note.dao;
import note.entity.Emp;
import note.util.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class EmpDaoTest {
SqlSession sqlSession = null;
EmpDao empDao = null;
@Before
public void setUp() throws Exception {
sqlSession = SqlSessionUtil.getSqlSession();
empDao = sqlSession.getMapper(EmpDao.class);
}
@After
public void tearDown() throws Exception {
if (sqlSession != null) {
sqlSession.close();
}
}
@Test
public void selectEmpByEid() {
Emp emp = empDao.selectEmpById(2);
System.out.println(emp);
}
@Test
public void selectEmpByEid2() {
Emp emp = empDao.selectEmpById2(2);
System.out.println("emp.getName() = " + emp.getName());
System.out.println("emp.getDep() = " + emp.getDep());
}
}
mybaitis 的缓存
- MyBatis 的缓存是一种可选的提高性能的方式,它可以缓存查询结果,避免反复查询数据库,减少与数据库的交互次数,提高系统性能。MyBatis 中的缓存主要分为一级缓存和二级缓存,本质上都是一个内存区域,在不同的作用域内起作用。
- 一级缓存:一级缓存也称为本地缓存,它是在
SqlSession 对象的生命周期内有效。当前 SqlSession 内多次查询相同数据,第一次查询后,数据将会被缓存在本地内存中,等待下一次请求使用,从而避免重复查询,降低数据库压力。 - 一级缓存是 MyBatis 默认开启的,如果某个
SqlSession 关闭了或者提交了事务,则该 SqlSession 的一级缓存也将被清空。一级缓存是基于对象引用的,查询结果是以 Map 为基础进行存储,其中 key 是 SQL 语句和查询条件组成的唯一标识符,value 是对应的查询结果所对应的 Java 对象。
- 二级缓存:二级缓存也称为全局缓存,它是基于命名空间的缓存,多个
SqlSession 可以共享同一个命名空间的缓存数据。二级缓存的作用域是同一个 Mapper(namespace)下。 - 二级缓存需要通过配置开启,其默认是关闭的。可以设置缓存的实现方式,默认情况下,MyBatis 提供了多种缓存实现,包括延迟加载缓存(LruCache)、FIFO 缓存(FifoCache)、SoftReference 缓存(SoftCache)、弱引用缓存(WeakCache)等。用户也可以自定义缓存实现策略。
- 需要注意的是,缓存虽然可以提高系统性能,但是如果缓存数据过多、过期配置不合理或者缓存策略不当,反而会降低系统性能,甚至导致数据一致性问题。因此,应该根据具体情况和需求选择合适的缓存方案,并进行有效的缓存监控和管理,确保缓存的正常运行和数据一致性。
package note;
import note.dao.EmpDao;
import note.util.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
public class CacheNote {
public static void main(String[] args) {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpDao EmpDao = sqlSession.getMapper(EmpDao.class);
System.out.println("第一次查询selectEmpById2(1)---------------");
System.out.println("EmpDao.selectEmpById2(1) = " + EmpDao.selectEmpById2(1));
System.out.println("第一次查询selectEmpById2(2)---------------");
System.out.println("EmpDao.selectEmpById2(2) = " + EmpDao.selectEmpById2(2));
System.out.println("第二次查询selectEmpById2(2)---------------");
System.out.println("EmpDao.selectEmpById2(2) = " + EmpDao.selectEmpById2(2));
System.out.println("第二次查询selectEmpById2(1)---------------");
System.out.println("EmpDao.selectEmpById2(1) = " + EmpDao.selectEmpById2(1));
sqlSession.commit();
SqlSession sqlSession2 = SqlSessionUtil.getSqlSession();
EmpDao EmpDao2 = sqlSession2.getMapper(EmpDao.class);
System.out.println("第三次查询selectEmpById2(1)(不同的sqlSession)---------------");
System.out.println("EmpDao.selectEmpById2(1) = " + EmpDao2.selectEmpById2(1));
sqlSession.close();
}
}