MyBatis
后续还会更新.
建议找个视频结合着看
一、简介及基础应用
1.1、框架概念
框架就是软件的半成品,完成啦软件开发过程中的通用操作,程序员只需很少或者不用进行加工就能够实现待定的功能,
从而简化开发人员在软件开发中的步骤,提高开发效率;
1.2、常用框架
- MVC框架:简化啦Servle的开发步骤
- Struts2
- SpringMVC
- 持久层框架:完成数据库操作的框架
- apache DBUtils
- Hibernate
- Spring JPA
- MyBatis
- Spring框架
1.3、MyBatis介绍
MyBatis是一个半自动的ORM框架
ORM(Object Relational Mapping)对象关系映射,将Java中的一个对象与数据表中一行记录一一对应
ORM框架提供啦实体类与数据库的映射关系,通过映射文件的配置,实现对象的持久化
- MyBatis的前身是IBatis,是Apache软件基金会提供的一个开源项目
- 2010年iBatis迁移到谷歌,正式更名为MyBatis
- 2013年迁移到Github托管
- MyBatis特点:
- 支持自定义SQL、存储过程
- 对原有的JDBC进行封装,几乎消除啦所有JDBC代码,让开发者只需关注SQL本身
- 支持XML和注解配置方式自动完成ORM操作实现结果映射
二、框架部署
2.1、在idea中创建一个Maven项目
- 可以选择java工程
- 也可以选择web工程
2.2、在项目中添加MyBatis依赖
-
在pom.xml中添加依赖
-
mybtis
-
mysql driver
<!--mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <!--MyBatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency>
-
2.3、创建自定义模板
(下面代码是MyBatis配置文件的模板,idea怎么自定义模板可以百度)
要是不想创建的话可以每次都复制这段代码,麻烦一点而已
<?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>
</configuration>
2.4、创建MyBatis配置文件
放在resources文件夹中,名为“mybatis-config”,里面配置啦 数据库的连接信息,要有JDBC基础
<?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>
<!--在environments配置数据库连接信息-->
<!-- 在environments可以定义多个environment标签,每个environment标签可以定义一套连接配置-->
<!-- default属性指定使用哪个数据库-->
<environments default="mysql">
<environment id="mysql">
<!-- 用于配置数据库管理方式-->
<transactionManager type="JDBC"></transactionManager>
<!-- 用于配置数据库连接信息-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!-- 要连接的数据库-->
<property name="url" value="jdbc:mysql://localhost:3306/test1?characterEncoding=utf-8"/>
<!-- 账号-->
<property name="username" value="root"/>
<!-- 密码-->
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
</configuration>
三、MyBatis框架使用
3.1、创建实体类和对应的数据库表
(数据库表的列名 就是这些属性名,这里不提供数据库表)看截图创建吧
package com.xxp.pojo;
import lombok.*;
/**
* 创建实体类,与数据库列对应
* @author 86155
*/
@Getter
@Setter
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private int sId;
private String stuNum;
private String stuName;
private String stuGender;
private int stuAge;
}
3.2、创建Dao接口,用于对数据库操作
(结构看图片)
package com.xxp.dao;
import com.xxp.pojo.Student;
/**
* @author 86155
*/
public interface StudentDao {
/**
* 添加学生信息
* @param student
* @return
*/
public int inster(Student student);
}
3.3、创建mapper.xml文件
-
在resource下创建mapper文件夹,放置mapper.xml
-
在mapper.xml中写对数据库的操作
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--mapper文件相当于Dao接口的实现类,namspace属性要指定 所需要实现Dao接口的全限定名(即路径)--> <mapper namespace="com.xxp.dao.StudentDao"> <!--id是Dao接口名 parameterType是指定接口参数类型,不写也没关系--> <insert id="insterInfom" parameterType="com.xxp.pojo.Student"> insert into tb_student(stu_num,stu_name,stu_gender,stu_age) values (#{stuNum},#{stuName},#{stuGender},#{stuAge}) </insert> </mapper>
-
在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>
<!--在environments配置数据库连接信息-->
<!-- 在environments可以定义多个environment标签,每个environment标签可以定义一套连接配置-->
<!-- default属性指定使用哪个数据库-->
<environments default="mysql">
<environment id="mysql">
<!-- 用于配置数据库管理方式-->
<transactionManager type="JDBC"></transactionManager>
<!-- 用于配置数据库连接信息-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306//student?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="******"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mappers/StudentMapper.xml"></mapper>
</mappers>
</configuration>
四、JUnit单元测试
4.1、使用方式
-
在pom.xml中添加依赖
-
<!-- junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13</version> <scope>test</scope> </dependency>
-
在要测试的接口处鼠标右键选择Generate-----Test----选择junit版本–勾选要测试的接口
-
会自动生成对应的测试类
-
在测试类中操作(注意可能会报错,因为数据库有事务)
public class StudentDaoTest { @org.junit.Test public void insterInfom() { try { //获取配置文件 InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml"); //工厂模式,创建会话工厂必备 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //创建会话工厂,需要连接信息,连接信息在mybatis配置文件中,见第一步 SqlSessionFactory factory = builder.build(resourceAsStream); //从工厂中获取sqlSession对象,注意sqlSession是mybatis的操作对象 SqlSession sqlSession = factory.openSession(); //获取studentDao的对象,对象在sqlSession中被创建 StudentDao studentDao = sqlSession.getMapper(StudentDao.class); int i = studentDao.insterInfom(new Student(0, "10001", "张三", "男", 21)); System.out.println(i); } catch (IOException e) { e.printStackTrace(); } } }
五、MyBatis的CRUD操作
案例还是student表
这里介绍一下:标签里面几个参数:
- resulType=""返回值类型
- resulMap =""关系映射id,有时候返回值是实体类类型,需要做关系映射,后续会介绍
- parameterType=”“实体类参数类型
这里可能不理解,后续第八章会详细介绍这些参数,这里先学会怎么用
5.1、添加操作
见上面代码
5.1.2、主键回填
有时候业务需要,要拿到所添加元素的主键值,然后进行下一步操作,这时候就主键回填
在mapper配置文件中 inser标签添加 useGeneratedKeys=“true” keyProperty=""两个参数
useGeneratedKeys=“true” 表示开启主键回填
keyProperty里面的值是你要回填到哪里:比如student类中的sid
<insert id="insterInfom" parameterType="com.xxp.pojo.Student" useGeneratedKeys="true" keyProperty="sid">
insert into
tb_students(sid,stu_num,stu_name,stu_gender,stu_age)
values
(#{sId},#{stuNum},#{stuName},#{stuGender},#{stuAge})
</insert>
@org.junit.Test
public void insterInfom() {
try {
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//工厂模式,创建会话工厂必备
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//获取会话工厂,需要连接信息,连接信息在mybatis配置文件中,见第一步
SqlSessionFactory factory = builder.build(resourceAsStream);
//从工厂中获取sqlSession对象,注意sqlSession是mybatis的操作对象
SqlSession sqlSession = factory.openSession();
// 获取studentDao的对象,对象在sqlSession中被创建
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = new Student(3, "10005", "老六", "男", 21);
int i = studentDao.insterInfom(student);
//获取到回填的id
System.out.println(student.getSId());
sqlSession.commit();
} catch (IOException e) {
e.printStackTrace();
}
5.2、删除操作
根据学号删除学生信息
-
在studentDao中添加删除接口
/** * 删除学生信息 * @param stuNum * @return */ int deleteInfom(String stuNum);
-
在studentMapper.xml文件中输入sql语句
-
<delete id="deleteInfom"> delete from tb_student where stu_num=#{stuNum} </delete>
-
使用junit测试
-
@Test public void testDeleteStudent(){ try { InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml"); //工厂建造者,有工厂建造者才能建造工厂 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //构建会话工厂 SqlSessionFactory factory = builder.build(resourceAsStream); // 创建sqlsession sqlSession是mybatis与数据库之间的会话 SqlSession sqlSession = factory.openSession(); //获取到mybatis创建的StudentDao代理对象 动态代理 StudentDao studentDao = sqlSession.getMapper(StudentDao.class); int infom = studentDao.deleteInfom("10001"); //提交事务 sqlSession.commit(); System.out.println(infom); } catch (IOException e) { e.printStackTrace(); } }
5.3、修改操作
根据学号修改学生信息
- 在studentDao中添加修改学生接口
/**
* 修改学生信息
* @param student
* @return
*/
int updateStudent(Student student);
- 在mybatis-config.xml中添加sql语句
<!-- 修改学生信息-->
<update id="updateStudent" parameterType="com.xxp.pojo.Student">
update tb_students set
stu_name=#{stuName},stu_gender=#{stuGender},stu_age=#{stuAge}
where
stu_num=#{stuNum}
</update>
- 使用junit测试接口
@Test
public void updateStudent(){
try {
//加载mybatis配置文件,获取到连接信息
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//构建工厂建造者
SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
//创建会话工厂
SqlSessionFactory factory = factoryBuilder.build(resourceAsStream);
//创建sqlSession
SqlSession sqlSession = factory.openSession();
// 从sqlSession中获取到代理对象StudentDao
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
int i = studentDao.updateStudent(new Student(0, "10001", "李四", "女", 23));
sqlSession.commit();
//断言测试,第一个参数是你期望返回的值,第二个参数是实际返回的值
assertEquals(0,i);
sqlSession.close();
} catch (IOException e) {
e.printStackTrace();
}
}
5.4、查询操作
5.4.1、查询所有操作
-
在studentDao中添加查询学生接口
/** * 查询所有学生信息 * @return */ List<Student> selectStudents();
-
在studentMapper.xml文件中写查询语句
==注意:==这里返回的结果为student对象,所以必须做关系映射,即数据库中字段名必须和实体类的名字一致
这里采用第一种方式:起别名的方式
<select id="selectStudents" resultType="com.xxp.pojo.Student"> select sid sId,stu_num stuNum,stu_name stuName,stu_gender stuGender,stu_age stuAge from tb_students </select>
这里介绍第二种映射方式:resultMap标签
<!-- resultMap id="" id可以任意 尽量写实体类名字 colum是数据库的字段名 property是实体类的变量名 -->
<resultMap id="studentMap" type="com.xxp.pojo.Student">
<id column="sid" property="sId"/>
<result column="stu_num" property="stuNum"/>
<result column="stu_name" property="stuName"/>
<result column="stu_gender" property="stuGender"/>
<result column="stu_age" property="stuAge"/>
</resultMap>
<!-- 查询所有学生信息 resutMap 参数值为resultMap的id名-->
<select id="selectStudents" resultMap="studentMap">
select
sid ,stu_num,stu_name,stu_gender,stu_age
from
tb_students
</select>
-
使用junit测试
@Test public void selectStudents(){ //获取mybatis-config.xml文件 里面有连接数据库的信息 sqlSession需要 try { InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml"); //创建工厂建造者 SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder(); //创建会话工厂 SqlSessionFactory factory = factoryBuilder.build(resourceAsStream); //对数据库操作 SqlSession sqlSession = factory.openSession(); //获取sqlsession创建的代理对象StudentDao StudentDao studentDao= sqlSession.getMapper(StudentDao.class); List<Student> students = studentDao.selectStudents(); sqlSession.commit(); for (Student s:students) { System.out.println(s); } } catch (IOException e) { e.printStackTrace(); } }
5.4.1、根据主键查询
-
在studentDao中添加查询接口
/** * 根据学号查询学生信息 * @return */ Student selectStudentBystuName(String stuNum);
-
在studentMapper.xml文件中写查询语句
<!--根据学号查询学生信息-->
<select id="selectStudentBystuName" resultMap="studentMap">
select
sid ,stu_num,stu_name,stu_gender,stu_age
from
tb_students
where stu_num=#{stuNum}
</select>
- 使用junit测试
@Test
public void selectStudentBystuName(){
//加载mybatis-config.xml文件 里面有连接数据库的信息
try {
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//构建工厂建造者
SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
//创建会话工厂
SqlSessionFactory factory = factoryBuilder.build(resourceAsStream);
//从会话工厂拿到sqlSession
SqlSession sqlSession = factory.openSession();
//获取sqlSession创建的代理对象studentDao
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = studentDao.selectStudentBystuName("10001");
sqlSession.commit();
System.out.println(student);
sqlSession.close();
} catch (IOException e) {
e.printStackTrace();
}
5.4.2、查询记录数
-
在studentDao中添加查询接口
/** * 查询记录条数 * @return */ int selectCount();
-
在studentMapper.xml文件中写查询语句
-
<select id="selectCount" resultType="int"> select count(1) from tb_students; </select>
-
使用junit测试
-
@Test public void selectCount() { //加载mybatis-config.xml文件 里面有连接数据库的信息 try { InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml"); //构建工厂建造者 SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder(); //创建会话工厂 SqlSessionFactory factory = factoryBuilder.build(resourceAsStream); //从会话工厂拿到sqlSession SqlSession sqlSession = factory.openSession(); //获取sqlSession创建的代理对象studentDao StudentDao studentDao = sqlSession.getMapper(StudentDao.class); int count = studentDao.selectCount(); sqlSession.commit(); System.out.println(count); sqlSession.close(); } catch (IOException e) { e.printStackTrace(); } }
5.4.3、多参数问题(例:分页查询)
这里说一下mybatis识别Dao接口中方法参数的问题:
mybatis中操作的方法参数只有一个时:
- 参数只有一个简单类型或者字符串类型时,在Mapper配置文件中可以之间通过#{参数名}的方式获取
- 参数为对象类型时,可以通过#{对象属性名}的方式获取
注意:mysql中使用limit可以实现分页查询,但是它需要两个参数,但是在mybatis中Dao接口中的方法参数为2个时MyBatis是没办法识别的。
下面来说解决办法多参数的解决办法:
- 可以使用HashMap作为参数,因为HashMap为<key,value>类型,在Mapper配置文件中可以之间通过#{key}获取到对应的value
上面方法只能解决有两个参数的问题,如果有2个以上的参数就可以采取下面这些方式:
第一种方式 在mapper文件写sql语句时使用 #{arg0},#{arg1}
第二种方式在mapper文件写sql语句时使用#{param1},#{param2}
上面两种方式存在一个问题 :参数的顺序必须记清楚,所以建议采用下面这种方式
第三种方式 在Dao接口定义操作方法时,如果方法有多个参数在参数前面加上==@Param==注解 起别名 看代码
/**
* 分页查询
* @return
*/
List<Student> selectStudentsByPage(@Param("start") int start, @Param("pageSize") int pageSize);
<!-- 分页查询-->
<select id="selectStudentsByPage" resultMap="studentMap">
select * from tb_students limit #{start},#{pageSize}
</select>
@Test
public void selectStudentsByPage(){
// 加载mybaitis-config文件里面有连接数据的信息
try {
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//创建工厂建造者
SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
//创建会话工厂
SqlSessionFactory sqlSessionFactory = factoryBuilder.build(resourceAsStream);
//创建sqlsession
SqlSession sqlSession = sqlSessionFactory.openSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Student> students = studentDao.selectStudentsByPage(0, 2);
sqlSession.commit();
for (Student s:students) {
System.out.println(s);
}
} catch (IOException e) {
e.printStackTrace();
}
}
5.5、(工具类)对Sqlsession获取进行封装
在上面你会发现每次都要写很多获取Sqlsession的重复代码,所以可以提取出来封装成工具类,使用的时候之间调用,实现面向对象编程。
这个就是工具类
/**
* @author 86155
* 获取sqlSession
*/
public class MyBatisUtil {
private static SqlSessionFactory factory;
//给sqlSession加锁
private static final ThreadLocal<SqlSession> LOCAL=new ThreadLocal<SqlSession>();
static {
try {
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//工厂模式,创建会话工厂必备
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//构建会话工厂,需要连接信息,连接信息在mybatis配置文件中
factory = builder.build(resourceAsStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
SqlSession sqlSession = LOCAL.get();
//第一次sqlSession没有被创建所以执行这一步
if (sqlSession==null){
sqlSession = factory.openSession();
LOCAL.set(sqlSession);
}
return sqlSession;
}
/**
* 这个方法只适用于不需要提交事务管理的方法
* @param c
* @param <T>
* @return
*/
public static <T extends Object>T getMapper(Class<T> c){
SqlSession sqlSession = getSqlSession();
T mapper = sqlSession.getMapper(c);
return mapper;
}
}
//对工具类进行测试
@Test
public void selectCount() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
//获取sqlSession创建的代理对象studentDao
StudentDao studentDao = MyBatisUtil.getMapper(StudentDao.class);
int count = studentDao.selectCount();
System.out.println(count);
sqlSession.close();
}
六、事务操作
上面做完对数据库的增、删、改操作后都需要手动提交事务,这里介绍mybats的事务管理
SqlSession对象的方法
- getMapper():获取Mapper(DAO接口的实例)
- 事务管理相关方法(下面详细介绍)
6.1、手动提交事务
涉及到两个方法:
commit():提交事务
rollback():事务回滚
public void insterInfom() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
try {
// 获取studentDao的对象,对象在sqlSession中被创建
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = new Student(3, "10005", "老六", "男", 21);
int i = studentDao.insterInfom(student);
System.out.println(student.getSId());
//提交事务
sqlSession.commit();
} catch (Exception e) {
//如果出现异常就回滚
sqlSession.rollback();
}
}
6.2、自动提交事务
在Mybatis中可以设置自动提交事务
通过SqlsessionFactory调用openSession()方式时可以设置自动提交事务
factory.openSession()参数是 true表示自动提交事务,false或者不写表示不提交事务
对工具类优化
/**
* @author 86155
* 获取sqlSession
*/
public class MyBatisUtil {
private static SqlSessionFactory factory;
//给sqlSession加锁
private static final ThreadLocal<SqlSession> LOCAL=new ThreadLocal<SqlSession>();
static {
try {
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//工厂模式,创建会话工厂必备
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//构建会话工厂,需要连接信息,连接信息在mybatis配置文件中
factory = builder.build(resourceAsStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
*
* @param isAutoCommit ture/false
* @return
*/
public static SqlSession getSqlSession(Boolean isAutoCommit){
SqlSession sqlSession = LOCAL.get();
//第一次sqlSession没有被创建所以执行这一步
if (sqlSession==null){
sqlSession = factory.openSession(isAutoCommit);
LOCAL.set(sqlSession);
}
return sqlSession;
}
/**
* 这个方法只适用于不需要提交事务管理的方法
* @param c
* @param <T>
* @return
*/
public static <T extends Object>T getMapper(Class<T> c){
SqlSession sqlSession = getSqlSession(true);
T mapper = sqlSession.getMapper(c);
return mapper;
}
}
@Test
public void testDeleteStudent(){
StudentDao studentDao = MyBatisUtil.getMapper(StudentDao.class);
int infom = studentDao.deleteInfom("10001");
//提交事务
System.out.println(infom);
}
==注意:==当你对数据库有多个操作时不建议自动提交事务。建议所有操作完成后手动提交
七、MyBatis主配置文件介绍
这里详细介绍一下Mybatis的主配置文件,mybatis-config.xml文件
注意一点的是:这些标签必须按顺序写,否则会报错
7.1、properties标签
可以用于设置键值对,或者加载属性文件(引用外部文件)
-
在resource目录下创建jdbc.properties文件,内容如下
mysql_driver=com.mysql.jdbc.Driver mysql_url=jdbc:mysql://localhost:3306/student?characterEncoding=utf-8 mysql_username=root mysql_password=256793
-
在mybatis-config.xml中通过properties标签引用jdbc.properties文件,引入之后enviroments可以直接使用jdbc.properties的key获取对应的value
<?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> <!--引用外部jdbc.properties文件--> <properties resource="jdbc.properties"></properties> <!--在environments配置数据库连接信息--> <!-- 在environments可以定义多个environment标签,每个environment标签可以定义一套连接配置--> <!-- default属性指定使用哪个数据库--> <environments default="mysql"> <environment id="mysql"> <!-- 用于配置数据库管理方式--> <transactionManager type="JDBC"></transactionManager> <!-- 用于配置数据库连接信息--> <dataSource type="POOLED"> <property name="driver" value="${mysql_driver}"/> <property name="url" value="${mysql_url}"/> <property name="username" value="${mysql_username}"/> <property name="password" value="${mysql_password}"/> </dataSource> </environment> </environments> <mappers> <mapper resource="mappers/StudentMapper.xml"></mapper> </mappers> </configuration>
7.2、settings标签
<settings>
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
<!-- 开启懒加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
7.3、typeAliases标签
用于给实体类起别名
<!-- typeAliases标签用于给实体类取别名,在映射文件中可以直接使用别名代替全限定名 -->
<typeAliases>
<typeAlias type="com.xxp.pojo.Student" alias="Student"></typeAlias>
</typeAliases>
映射文件
<resultMap id="studentMap" type="Student">
<id column="sid" property="sId"/>
<result column="stu_num" property="stuNum"/>
<result column="stu_name" property="stuName"/>
<result column="stu_gender" property="stuGender"/>
<result column="stu_age" property="stuAge"/>
</resultMap>
7.4、plugins标签
配置mybatis的插件,比如分页插件
7.5、environments标签
<!--在environments配置数据库连接信息--> <!-- 在environments可以定义多个environment标签,每个environment标签可以定义一套连接配置--> <!-- default属性指定使用哪个数据库-->
environments子标签transactionManager标签
<environments default="mysql">
<environment id="mysql">
<!-- 用于配置数据库管理方式-->
<!-- type=“JDBC” 可以进行事务的提交和回滚事件
type=“MANAGED”可以依赖容器完成事务管理,让自己不用进行事务的提交和回滚
-->
<transactionManager type="JDBC"></transactionManager>
<!-- 用于配置数据库连接信息 type配置连接池 后续会详细介绍-->
<dataSource type="POOLED">
<property name="driver" value="${mysql_driver}"/>
<property name="url" value="${mysql_url}"/>
<property name="username" value="${mysql_username}"/>
<property name="password" value="${mysql_password}"/>
</dataSource>
</environment>
</environments>
7.6、mappers标签
载入映射文件、或者Dao注解
<mappers>
<mapper resource="mappers/StudentMapper.xml"></mapper>
</mappers>
八、映射文件介绍(mapper.xml)
8.1、mapper标签
mapper文件相当于DAO接口的实现类,namespace属性要指定实现DAO的全限定名
8.2、insert标签
声明添加操作
常用属性:
- id属性:绑定对应DAO接口中的方法
- parameterType属性:指定对应接口方法的参数类型(可以省略)
- useGeneratedKeys属性:设置添加操作是否需要主键回填
- keyProperty属性:指定回填的id设置到参数对象的哪个属性中
- timeout属性:设置此操作的超时时间,如果不设置会一直等待
8.3、delete标签
声明删除操作。属性与insert一致
8.4、updata标签
声明修改操作 属性与insert一直
8.5、select标签
声明查询操作
常用属性:
id属性:绑定对应DAO接口中的方法
parameterType属性:指定对应接口方法的参数类型(可以省略)
resultType:指定当前sql返回数据封装的对象类型(实体类)
resultMap属性:指定从数据表到实体类的字段和属性的对应关系
useCache属性:指定查询操作是否需要缓存
timeout属性:设置此操作的超时时间,如果不设置会一直等待
8.6、resultMap标签
用于定义实体类与数据表的映射关系(ORM)
8.7、cache标签
设置当前DAO进行数据库操作时的缓存属性设置
8.9、sql和include标签
sql标签可以把那些重复的sql语句定义一遍,然后接下来要使用的话可以直接使用include标签调用,看代码:
<sql id="student">
sid ,stu_num,stu_name,stu_gender,stu_age
</sql>
<!-- 查询所有学生信息 resuttype 参数值为resultMap的id名-->
<select id="selectStudents" resultMap="studentMap">
select
<include refid="student"></include>
from
tb_students
</select>
九、动态sql
案例:心仪对象搜索
9.1.1、创建数据库表
create table members(
member_id int primary key auto_increment,
member_nick varchar(20) not null unique,
member_gender char(2) not null,
member_age int not null,
member_city varchar(30) not null
);
9.2.1、创建实体类
@Data
@Setter
@Getter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Member {
private int memberId;
private String memberNick;
private String memberGender;
private int memberAge;
private String memberCity;
}
9.2.2、创建参数类
@Data
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class MemberSearch {
private Integer maxAge;
private Integer minAge;
private String memberNick;
private String memberGender;
private String memberCity;
}
9.2.3、创建mapper文件(这里用到动态sql的if标签)
<mapper namespace="com.xxp.dao.MemberDAO">
<resultMap id="MemberMap" type="com.xxp.pojo.Member">
<id column="member_id" property="memberId"></id>
<result column="member_nick" property="memberNick"></result>
<result column="member_gender" property="memberGender"></result>
<result column="member_age" property="memberAge"></result>
<result column="member_city" property="memberCity"></result>
</resultMap>
<select id="searchMember" resultMap="MemberMap">
select * from members
where 1=1
<if test="memberCity !=null" >
and member_city=#{memberCity}
</if>
<if test="maxAge !=null">
and member_age <=#{maxAge}
</if>
<if test="minAge !=null">
and member_age>=#{minAge}
</if>
<if test="memberCity!=null">
and member_city=#{memberCity}
</if>
</select>
</mapper>
9.2.4、测试类
@Test
public void searchMember() {
MemberDAO memberDAO = MyBatisUtil.getMapper(MemberDAO.class);
MemberSearch memberSearch = new MemberSearch();
memberSearch.setMemberCity("河南");
memberDAO.searchMember(memberSearch);
}
}
9.2.5、其他标签
trim标签:
- prefix属性拼接前缀
prefixOverrides 忽略指定条件
suffix 可以拼接后缀
where标签简单不做介绍
foreach标签 用来遍历集合
属性:
- collection 集合名字
item 遍历集合中的元素赋值给谁,自己起个名字
separator多个元素之间用什么隔开
open 以什么开头
close 以什么结尾
9.3、模糊查询#{}和${}
#{key}表示获取参数,先完成SQL编译(预编译),预编译之后再将获取的参数设置到SQL中
${key}表示获取参数,先获取参数的值拼接到SQL语句中,在编译执行SQL语句
十、MyBatis日志配置
MyBatis作为一个封装好的ORM框架,其运行过程我们没办法跟踪,为啦让开发者了解MyBatis执行流程及每个执行步骤所完成的工作,MyBatis框架本身支持log4j日志框架。我们只需要对MyBatis进行相关配置就可以看到运行过程中的日志信息
10.1、加入log4j依赖
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
10.2、在resources中添加log4j.properties文件
内容是固定的可以创建个模板
#debug < info < warn < error
log4j.rootLogger=${logger.rootlogger}
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.Target=System.out
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%-5d [%-4p] [%r] [%t] [%l] - %m%n
# root info
log4j.appender.Infofile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.Infofile.file=${catalina.home}/logs/ec.log
log4j.appender.Infofile.DatePattern='.'yyyy-MM-dd
log4j.appender.Infofile.layout=org.apache.log4j.PatternLayout
log4j.appender.Infofile.layout.ConversionPattern=%-5d [%-4p] [%r] [%t] [%l] - %m%n
# error
log4j.appender.Errorfile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.Errorfile.file=${catalina.home}/logs/error.log
log4j.appender.Errorfile.DatePattern='.'yyyy-MM-dd
log4j.appender.Errorfile.Threshold=ERROR
log4j.appender.Errorfile.layout=org.apache.log4j.PatternLayout
log4j.appender.Errorfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n
# 输出liveness日志
log4j.logger.liveness=INFO, liveness
# 是否在父log中输出日志
log4j.additivity.liveness=false
# 每天生产日志文件
log4j.appender.liveness=org.apache.log4j.DailyRollingFileAppender
# 生成日志到单独的文件
log4j.appender.liveness.File=${catalina.home}/logs/liveness.log
# 追加日志
log4j.appender.liveness.Append=true
# 日志级别
log4j.appender.liveness.Threshold=INFO
log4j.appender.liveness.layout=org.apache.log4j.PatternLayout
# 日志格式
log4j.appender.liveness.layout.ConversionPattern=[%p] [%-d{yyyy-MM-dd HH:mm:ss}] %C.%M(%L) | %m%n
十一、Druid连接池
MyBatis在进行数据库操作时是需要和数据库链接的,MyBatis支持基于数据库连接池的链接创建方式。
当我们配置Mybatis的数据源时,只要配置啦dataSource标签的type属性值为POOLED时,就可以使用MyBatis内置的连接池管理链接
如果需要使用第三方数据库连接池,则需要进行自定义配置。
11.1、常见的链接池
- DBCP
- C3P0
- Druid(阿里开发) 性能好,扩展性好,提供比较好的监控系统(目前使用最多)
- Hikal 性能最高
11.2、添加Druid依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.5</version>
</dependency>
11.3、配置Druid连接池
配置mybatis-config文件
<environments default="mysql">
<environment id="mysql">
<!-- 用于配置数据库管理方式-->
<transactionManager type="JDBC"></transactionManager>
<!-- 用于配置数据库连接信息-->
<dataSource type="com.xxp.util.DruidDataSourceFactory">
<property name="driverClass" value="${mysql_driver}"/>
<property name="jdbcUrl" value="${mysql_url}"/>
<property name="username" value="${mysql_username}"/>
<property name="password" value="${mysql_password}"/>
</dataSource>
</environment>
</environments>
创建DruidDataSourceFactory 类
/**
* 配置Druid连接池
* @author xxp
*/
public class DruidDataSourceFactory extends PooledDataSourceFactory {
public DruidDataSourceFactory(){
this.dataSource=new DruidDataSource();
}
}
十二、Mybatis缓存
Mybatis时基于JDBC的封装,使数据库操作更加便捷;MyBatis除啦对JDBC操作步骤进行封装之外还对其性能进行啦优化:
在mybatis中引入缓存机制,用于提升检索效率
mybatis缓存分为一级缓存和二级缓存
12.1、MyBatis的一级缓存步骤
MyBtais一级缓存默认是开启的。
一级缓存也叫Sqlsession级别的缓存,为每个SqlSession单独分配缓存内存,无需手动开启可以直接使用,多个SqlSession的缓存是不共享的
特性:
1、如果多次查询使用的是同一个Sqlsession对象,则第一次查询之后数据会放到缓存,后续的查询则直接访问缓存
2、如果第一次查询完之后对查询的对象进行修改,该修改会影响缓存,第二次查询会访问缓存,造成第二次查询的结果与数据库结果不一致。(这里是对 对象数据修改,不是数据库数据)
3、当我们想跳过缓存直接查询数据库时,可以通过sqlsession.clearCache()方法清除缓存
4、如果第一次查询之后第二次查询之前,使用当前sqlSession执行啦修改操作,此操作会使第一次放在缓存的结果失效,因此第二次会再次访问数据库
工作步骤:
1、sqlsession拿到sql语句后会先在缓存中检查是否存在要查询的数据
2、如果存在直接返回数据,将不再去查询数据库
3、如果不存在就会去数据库查询数据后返回并在缓存中存储一份,以供下次使用
12.2、MyBatis的二级缓存步骤
二级缓存也称为SqlSessionFactory级缓存,通过同一个factory对象获取的sqlsession可以共享二级缓存;在应用服务器中sqlsessionfactory是单例的,因此我们的二级缓存可以实现全局共享;
特性:
1、二级缓存默认没有开启,需要在mybatis-config.xml中settings标签中开启
2、二级缓存只能缓存实现序列化接口的对象
注意:
多个sqlsession一定要共享一个sqlsessionFactory对象
一定要提交事务,二级缓存才会将结果缓存。
在mybatis-config.xml中开启二级缓存
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
在需要使用缓存的mapper中开启二级缓存
<cache/>
在mapper对应的实体类上实现序列化接口
@Data
@Setter
@Getter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Member implements Serializable {
private int memberId;
private String memberNick;
private String memberGender;
private int memberAge;
private String memberCity;
}
SqlSessionFactory对象并没有提供相应方法去控制二级缓存如果想修改二级缓存数据可以通过以下方式:
可以通过 **flushCache=“true”**来修改二级缓存的数据
useCache="true"来控制本次操作是否使用缓存
<update id="" flushCache="true" useCache="true">
</update>
十三、延迟加载
延迟加载–如果在Mybatis执行啦子查询(至少查询2次及以上),默认只执行第一次查询,当用到子查询的查询结果的时候才会触发子查询的执行,如果无需使用子查询结果,则不会进行查询。
在多表联查时用到的多
延迟加载分为:
直接加载:执行完对主加载对象的 select 语句,马上执行对关联对象的 select 查询。
侵入式延迟: 执行对主加载对象的查询时,不会执行对关联对象的查询。但当要访问主加载对象的详情属性时,就会马上执行关联对象的select查询。
深度延迟: 执行对主加载对象的查询时,不会执行对关联对象的查询。访问主加载对象的详情时也不会执行关联对象的select查询。只有当真正访问关联对象的详情时,才会执行对关联对象的 select 查询。
例如:这里多对一查询 子查询
<!--根据team的id查找player-->
<select id="selectPlayerByTeamId" resultType="Player">
select id,name from t_player WHERE tid=#{id}
</select>
<!--关联属性映射关系-->
<!--集合的数据来自select查询,该查询的条件是selectTeamByIdAlone查询出的id-->
<resultMap id="teamMapAlone" type="Team">
<id column="id" property="id"/>
<result column="name" property="name"/>
<collection property="playerList" ofType="Player" select="selectPlayerByTeamId" column="id"/>
</resultMap>
<select id="selectTeamByIdAlone" resultMap="teamMapAlone">
SELECT id,name FROM t_team where id=#{id}
</select>
配置延迟加载的方式,在mybatis-config.xml中配置:
<!--全局参数设置-->
<settings>
<!--延迟加载总开关-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--侵入式延迟加载开关 如果为false则开启深度延迟加载-->
<setting name="aggressiveLazyLoading" value="true"/>
</settings>
第二种方式是:
在resultMap标签中collection或association配置fetchType属性,这种方式比较具体谁使用谁配置。
fetchType的值:配置为lazy之后是开启深度延迟,配置eager是不开启深度延迟