Mybatis持久层应用框架
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。
Mybatis核心组件:
SqlSessionFactoryBuilder:会根据配置信息或代码来生成SqlSessionFactory;
SqlSessionFactory:依靠工厂来生成SqlSession;
SqlSession:是一个既可以发送SQL去执行并返回结果,也可以获取Mapper的接口;
SQL Mapper:是MyBatis新设计的组件,由一个Java接口和XML文件构成,需要给出对应的SQL和映射规则。它负责发送SQL去执行,并返回结果。
//加载配置文件到输入流
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//通过sqlsession工厂构建器加载资源配置文件构建 sqlsession工厂类
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂创建sqlsession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过sqlSession获取映射的Dao接口对象
StudentDao studentDao= sqlSession.getMapper(StudentDao.class);
//直接可以调用接口中定义的方法
studentDao.deleteStudent(1);
//手动提交事务,如要自动提交事务,需在sqlSessionFactory.openSession(true);添加true参数为自动提交
sqlSession.commit();
//关闭sqlSession
sqlSession.close();
//关闭输入流
inputStream.close();
单元测试JUnit
junit4中常用注解 @BeforeClass @Before @AfterClass @After @Test @Ignore
junit5中常用注解 @BeforeAll @BeforeEach @AfterAll @ AfterEach @Test
junit5 单元测试类:
class TestMyBatis {
static InputStream resourceAsStream;
static SqlSession sqlSession;
//第四步、通过sqlsession获取接口
static StudentDao studentDao;
@BeforeAll
static void init() throws Exception{
//第一步、通过resource获取mybatis的全局配置文件加载到输入流中
resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//第二步、使用工厂构建器通过全局配置文件mybatis-config.xml创建出一个sqlsession的工厂类
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(resourceAsStream);
//第三步、使用工厂创建出sqlsession
//SqlSession sqlSession = sqlSessionFactory .openSession();
//设置sqlsession自动提交事务,加一个参数true,不需要使用commit()
sqlSession = sqlSessionFactory .openSession(true);
//第四步、通过sqlsession获取接口
studentDao = sqlSession.getMapper(StudentDao.class);
}
@Test
void testSelectStudentById() throws Exception{
Student student = studentDao.selectStudentById(3);
System.out.println(student);
}
@Test
void testSelectAllStudents() throws Exception{
List<Student> ls = studentDao.selectAllStudents();
for(Student student : ls)
System.out.println(student);
}
@Test
void testUpdateStudent() throws Exception{
Student student = new Student(3,"李四",18);
int result = studentDao.updateStudent(student);
System.out.println(result);
}
@Test
void testDeleteStudent() throws Exception{
int result = studentDao.deleteStudent(2);
System.out.println(result);
}
@Test
void testInsertStudent() throws Exception{
int result = studentDao.insertStudent(new Student(4,"王六",23));
System.out.println(result);
}
@AfterAll
static void close() throws Exception{
sqlSession.close();
resourceAsStream.close();
}
}
junit4:
public class JunitTest {
@BeforeClass
public static void beforeClass() {
System.out.println("in before class");
}
@AfterClass
public static void afterClass() {
System.out.println("in after class");
}
@Before
public void before() {
System.out.println("in before");
}
@After
public void after() {
System.out.println("in after");
}
@Test
public void testCase1() {
System.out.println("in test case 1");
}
@Test
public void testCase2() {
System.out.println("in test case 2");
}
}
Mybatis增删改查
修改接口和映射文件
<mapper namespace="org.lanqiao.mapper.StudentMapper">
<insert id="insertStudent" parameterType="Student">
insert into student values(null,#{sname},#{sage})
</insert>
<delete id="deleteStudent" parameterType="Integer">
delete from student where sid = #{nid}
</delete>
<delete id="deleteStudent2" parameterType="Student">
delete from student where sid = #{sid}
</delete>
<update id="updateStudent" parameterType="Student">
update student set sname=#{sname},sage=#{sage} where sid=#{sid}
</update>
<select id="selectStudentById" parameterType="int" resultType="Student">
select * from student where sid = #{id}
</select>
<select id="selectAllStudents" resultType="Student">
select * from student
</select>
</mapper>
查询进阶
假如实体类Student sname ----》表student name 名字不一样怎么办?
假如sql是一个复杂的多表查询时,Student类无法完全匹配怎么办?
1.Resultmap的应用:
<resultMap type="Student" id="StudentResultMap">
<id property="id" column="sid" javaType="int" jdbcType="NUMERIC"/>
<result property="name" column="sname" javaType="String" jdbcType="VARCHAR"/>
<result property="age" column="sage" javaType="int" jdbcType="NUMERIC"/>
</resultMap>
作用:a.解决当实体类中包含其他的实体类时一种映射关系
b.当数据库的字段名和实体类的属性名不一致时
2.多表查询:
注:表的名字尽量不要使用关键字,比如分组表group,group就是SQL的一个关键字假如要使用的话,只能在group
,该`是键盘tab上面的那个按键
(1).一对一 association
学生表关联年级表(一对一关系)
对应的sql:
select * from student s,grade g where s.gid=g.gid
<resultMap type="Student" id="StudentResultMap">
<id property="id" column="sid" javaType="int" jdbcType="NUMERIC"/>
<result property="name" column="sname" javaType="String" jdbcType="VARCHAR"/>
<result property="age" column="sage" javaType="int" jdbcType="NUMERIC"/>
<association property="grade" column="gradeid" select="org.lanqiao.mapper.GradeMapper.selectGradeById" />
</resultMap>
这种做法的问题:sql语句变多,执行的次数增加,解决该问题使用:延迟加载(懒加载)、按需加载
需要修改全局配置文件mybatis-config.xml
<!--延迟加载,按需加载,需要什么就查什么,不需要的不会去查询-->
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
动态sql 动态SQL是基于OGNL(Object-Graph Navigation Language)表达式
动态sql主要功能:拼接SQL语句
做搜索功能
if
<if test=”id!=null and id!='“>
and sid = #{id}
</if>
<if test="name!=null and name!=''">
and sname like <bind name="name" value="'%'+_parameter.getName() +'%'"/>
</if>
<if test="age!=null and age!=''">
and sage = #{age}
</if>
模糊查询:
1.程序处理查询字符串stu.setName("%张%");
2.利用数据库的Concat函数 sname like CONCAT(CONCAT(’%’,#{name}),’%’),mysql和oracle都支持的
3.Mybatis提供bind动态sql
<bind name="name2" value="'%'+_parameter.getName() +'%'"/>
可以通过#{name2}取到value的值
4.使用
方
式
a
n
d
s
n
a
m
e
l
i
k
e
′
{}方式 and sname like '%
方式andsnamelike′{name}%’ “a or 1=1 and”
使用场景 select * from student order by ${sname}
根据一个字段进行查询排序
selectAllStudentOrderBy(String field);
注: 取 字 符 串 参 数 使 用 {}取字符串参数使用 取字符串参数使用{value}或${_parameter}
select * from student order by name //${field}
select * from student order by "name" //#{field}
<select>
select * from student order by #{field}
</select>
mybatis缓存机制 cache
- 一级缓存
有效范围:sqlsession
针对:查询操作
默认:开启
写入时间:查询后即写入缓存
如何判断使用一级缓存,根据你的执行sql和你传入的参数在sqlsession有效范围内
手动清除一级缓存:
1.sqlsession.close()
2.sqlsession.clearCache();
3.执行了insert,update,delete都会清除缓存 - 二级缓存
有效范围:设定全局,使用中有效范围是在一个namespace当中
针对:查询
默认:关闭
写入缓存时间:当查询完毕,关闭sqlsession才会写入缓存
二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的
因为被缓存的内容即对象需要保存到硬盘,就需要给对应的实体类进行序列化