一、开发步骤
- 创建Mybatis主配置文件:放在resources目录下
<?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">
<!-- mybatis的住配置文件 -->
<configuration>
<!-- 数据库连接信息的文件位置 -->
<properties resource="db.properties"></properties>
<!-- 配置信息 -->
<settings>
<!-- 延迟加载配置 -->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 二级缓存配置 -->
<setting name="cacheEnabled" value="true"/>
</settings>
<!-- 给包取别名 -->
<typeAliases>
<package name="pers.qianxian.entity"/>
</typeAliases>
<!-- 配置环境 -->
<environments default="mysql">
<!-- 配置mysql环境 -->
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 配置文件所在位置 -->
<!-- 方式一:使用xml配置的方式 -->
<!-- <mapper resource="pers/qianxian/dao/StudentDao.xml" />-->
<!-- 方式二:使用注解配置的方式 -->
<!-- <mapper class="pers.qianxian.dao.StudentDao" />-->
<!-- 适用于xml和注解的开发方式 -->
<package name="pers.qianxian.dao"/>
</mappers>
</configuration>
- 创建对应实体类的dao层接口:
public interface StudentDao {
List<Student> findAll();
Student findOne(String sid);
List<Student> findInList(QueryVo vo);
void insert(Student student);
void update(Student student);
void delete(String sid);
}
- 创建对应dao接口的mapper映射:(注意:映射文件放在resources文件夹,mapper映射文件需要和dao层接口所在包路径相同)
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace指定dao层接口的位置 -->
<!-- id表示接口的方法 -->
<mapper namespace="pers.qianxian.dao.StudentDao">
<!-- 定义一条sql语句,可以用include标签引用 -->
<sql id="defaultSelect">
select * from students
</sql>
<!-- select标签必须指定resultType或者resultMap -->
<select id="findAll" resultType="pers.qianxian.entity.Student">
select * from students
</select>
<select id="findInList" resultType="student"
parameterType="pers.qianxian.domain.QueryVo">
<include refid="defaultSelect" />
<!-- 动态sql部分 -->
<where>
<if test="ids != null and ids.size > 0">
<foreach collection="ids" open="and sid in (" close=")" item="id"
separator=",">
#{id}
</foreach>
</if>
</where>
</select>
<insert id="insert" parameterType="pers.qianxian.entity.Student">
insert into students(sid,sname,tel,email)
values(#{sid},#{sname},#{tel}, #{email})
</insert>
<update id="update" parameterType="pers.qianxian.entity.Student">
update students set sname=#{sname},tel=#{tel},email=#{email} where
sid=#{sid}
</update>
<delete id="delete" parameterType="string">
delete from students where sid=#{sid}
</delete>
</mapper>
- 测试dao层
public class Test {
public static void main(String[] args) throws IOException {
//1、读取主配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2、创建SqlSessionFactory
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3、创建SqlSession对象
SqlSession sqlSession = factory.openSession();
// 也可以传入true参数,表示自动提交
// SqlSession sqlSession = factory.openSession(true);
//4、使用SqlSession创建Dao接口的代理对象
StudentDao dao = sqlSession.getMapper(StudentDao.class);
//5、使用代理对象执行方法
List<Student> students = dao.findAll();
//6、关闭资源
sqlSession.commit();
sqlSession.close();
in.close();
}
}
二、properties标签
加载properties文件,然后可以用${键名}取到值:
<!-- properties文件位置 -->
<properties resource="db.properties"></properties>
三、一对一关联映射
一个学院有多个专业,一个专业只属于一个学院(在专业的mapper映射文件配置)
/**
* 学院实体类
*/
public class Academy {
private String aid;
private String aname;
private String tel;
private Set<Major> majors;
@Override
public String toString() {
return "Academy{" + "aid='" + aid + '\'' + ", aname='" + aname + '\'' + ", tel='" + tel + '\'' + ", majors=" + majors + '}';
}
public String getAid() {
return aid;
}
public void setAid(String aid) {
this.aid = aid;
}
public String getAname() {
return aname;
}
public void setAname(String aname) {
this.aname = aname;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
public Set<Major> getMajors() {
return majors;
}
public void setMajors(Set<Major> majors) {
this.majors = majors;
}
}
/**
* 专业实体类
*/
public class Major {
private String mid;
private String mname;
private String aid;
private Academy academy;
public String getMid() {
return mid;
}
public void setMid(String mid) {
this.mid = mid;
}
public String getMname() {
return mname;
}
public void setMname(String mname) {
this.mname = mname;
}
public String getAid() {
return aid;
}
public void setAid(String aid) {
this.aid = aid;
}
public Academy getAcademy() {
return academy;
}
public void setAcademy(Academy academy) {
this.academy = academy;
}
@Override
public String toString() {
return "Major{" + "mid='" + mid + '\'' + ", mname='" + mname + '\'' + ", aid='" + aid + '\'' + ", academy=" + academy + '}';
}
}
在majorDao.xml文件配置如下:
- 非延迟加载配置方式
<mapper namespace="pers.qianxian.dao.MajorDao">
<!-- id表示resultMap的唯一标识,type标识其对应实体类 -->
<resultMap id="majorMap" type="Major">
<!-- id标签配置主键 property是实体类属性名,column是对应表的字段名称 -->
<id property="mid" column="mid"></id>
<!-- result 标签配置非主键字段 property是实体类属性名,column是对应表的字段名称 -->
<result property="mname" column="mname"></result>
<result property="aid" column="aid"></result>
<!-- 配置一对一的映射: 普通配置方式 -->
<!-- property表示实体类属性名 column即外键字段 一定要加javaType(表示property的类型,因为要把 主表的信息封装到这个属性)
<association property="academy" column="aid" javaType="Academy">
<!-- 配置主表的主键字段 -->
<id property="aid" column="aid"></id>-->
<!-- 配置主表的非主键字段 -->
<result property="aname" column="aname"></result>
<result property="tel" column="tel"></result>
</association>
</resultMap>
<!-- 配合普通配置方式的sql语句 -->
<select id="findAll" resultMap="majorMap">
select academies.*,majors.mid,majors.mname
from majors,academies
where majors.aid=academies.aid
</select>
</mapper>
- 延迟加载配置方式(需要在主配置文件中开启延迟加载)
<mapper namespace="pers.qianxian.dao.MajorDao">
<resultMap id="majorMap" type="Major">
<id property="mid" column="mid"></id>
<result property="mname" column="mname"></result>
<result property="aid" column="aid"></result>
<!-- 配置一对一的映射: 延迟加载配置方式(注意:select语句就不再需要多表联合查询了)
select属性配置的是Academy根据id查询的dao层方法名
column是外键字段名
-->
<association property="academy" column="aid" javaType="Academy"
select="pers.qianxian.dao.AcademyDao.findById" />
</resultMap>
<!-- 配合延迟加载方式的sql语句 -->
<select id="findAll" resultMap="majorMap">
select * from majors
</select>
</mapper>
四、一对多的关联映射
实体类还是Academy和Major
在AcademyDao.xml中配置如下:
- 非延迟记载配置方式
<mapper namespace="pers.qianxian.dao.AcademyDao">
<resultMap id="academyMap" type="Academy">
<id property="aid" column="aid"></id>
<result property="aname" column="aname" />
<result property="tel" column="tel" />
<!-- 配置一对多映射: 普通配置方式 -->
<!-- property配置的是保存多的一方的属性名;ofType配置的是多的一方的实体类名 -->
<collection property="majors" ofType="Major">
<!-- 配置多的一方的表的个字段映射关系 -->
<id property="mid" column="mid" />-->
<result property="mname" column="mname" />
<result property="aid" column="aid" />
</collection>
</resultMap>
<!-- 配合普通配置方式使用 -->
<select id="findAll" resultMap="academyMap">
select academies.*,majors.mid,majors.mname
from academies left outer join majors
on academies.aid=majors.aid
</select>
</mapper>
- 延迟加载配置方式(需要在主配置文件开启延迟加载)
<mapper namespace="pers.qianxian.dao.AcademyDao">
<resultMap id="academyMap" type="Academy">
<id property="aid" column="aid"></id>
<result property="aname" column="aname" />
<result property="tel" column="tel" />
<!-- 配置一对多的映射:延迟加载配置方式 -->
<!-- column配置的是根据哪一列来查询多的一方
select配置的多的一方根据column字段查询的方法
注意:select配置的方法一定呀有一个参数
-->
<collection property="majors" ofType="Major" column="aid"
select="pers.qianxian.dao.MajorDao.findMajorsByAid"/>
</resultMap>
<!-- 配合延迟加载配置方式使用 -->
<select id="findAll" resultMap="academyMap">
select * from academies
</select>
</mapper>
五、关于Mybatis缓存
-
一级缓存
在SqlSession中的缓存,当SqlSession关闭时,缓存被清空,也可以用sqlSession.clearCache()来清空以及缓存;(一级缓存直接缓存的是对象,第二次查询不需要再封装成实体类) -
二级缓存
在SqlSessionFactory,同一个sqlSeesionFactory创建的不通过SqlSession对象共享一个缓存;(二级缓存保存的是“散装数据”,即键值对,封装为实体类的工作还是有) -
配置二级缓存(一级缓存默认是开启的)
步骤:
(1)在mybatis主要配置文件中配置如下信息:<settings> <setting name="cacheEnabled" value="true" /> </settings>
(2)让某个dao的映射文件(mapper)支持二级缓存:在mapper标签里加入 标签
(3)让某个查询使用二级缓存:在select标签加上useCache=“true”
映射文件配置信息如下【(2)(3)步】:
<mapper namespace="dao.StudentDao">
<cache />
<select id="findAll" resultType="Student" useCache="true">
select * from students
</select>
</mapper>
六、相关运行结果
- 关于延迟加载
public class Test {
public static void main(String[] args) throws IOException {
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
SqlSession sqlSession = factory.openSession();
AcademyDao academyDao = sqlSession.getMapper(AcademyDao.class);
List<Academy> academies = academyDao.findAll();
for (Academy academy : academies)
System.out.println(academy);
sqlSession.commit();
sqlSession.close();
in.close();
}
}
只等到需要用的时候才再次去加载,而没有一次性全部加载
- 关于一级缓存
public class MainTest {
private InputStream in;
private SqlSession sqlSession;
@Before
public void init() throws IOException {
in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = builder.build(in);
sqlSession = sqlSessionFactory.openSession(true);
}
@Test
public void testStudentDao() {
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Student> students1 = studentDao.findAll();
List<Student> students2 = studentDao.findAll();
Student student1 = null, student2 = null;
for (Student student : students1)
if (student.getSid().equals("20200001"))
student1 = student;
for (Student student : students2)
if (student.getSid().equals("20200001"))
student2 = student;
System.out.println(student1 == student2);
}
@After
public void destroy() throws IOException {
sqlSession.close(); // 此时一级缓存会消失
in.close();
}
}
可以看到,两次相同的查询,只取数据库查了一次
- 关于二级缓存