1、MyBatis 是一个 半自动的ORM(Object Relation Mapping)框架
2、mybatis支持定制化sql、存储过程、以及高级映射
3、支持jdbcTemplate模板,减少模板代码和硬编码
4、MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO映射成数据库中的记录
默认打开一级缓存,二级没有打开
一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就
会从缓存中直接获取,不会从数据库重新访问
不同的SqlSession对应不同的一级缓存
同一个SqlSession但是查询条件不同
同一个SqlSession两次查询期间执行了任何一次增删改操作
同一个SqlSession两次查询期间手动清空了缓存
二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被
缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取
a>在核心配置文件中,设置全局配置属性cacheEnabled=“true”,默认为true,不需要设置
b>在mapper映射文件中设置标签
c>二级缓存必须在SqlSession关闭或提交之后有效
d>查询的数据所转换的实体类类型必须实现序列化的接口
两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效
在mapper配置文件中添加的cache标签可以设置一些属性:
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。
FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新(清空缓存的意识)
代表缓存最多可以存储多少个对象,太大容易导致内存溢出
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了 很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。
先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
如果二级缓存没有命中,再查询一级缓存
如果一级缓存也没有命中,则查询数据库
SqlSession关闭之后,一级缓存中的数据会写入二级缓存
1、@Param注解可以设置参数的可以名,方便在mapper中 #{key} 或 ${key} 取值可以以这个key名
Student selectByNameId(@Param("name") String name, @Param("id") String id);
2、传入的参数是实体类,直接可以#{属性} 、${属性}获取属性值,
3、如上多个参数传入映射SQL,写在映射SQL中都是以rg1, arg0, param1, param2为键的map存储
4、@MapKey注解设置map集合的键,值是每条数据所对应的map集合
@MapKey("id") //设置每条数据的id为键值为整条数据,这样可以多条放入map中,如下是mapper接口方法
Map<String, Object> getAllUserToMap();
1、${}的本质就是字符串拼接,#{}的本质就是占位符赋值
2、${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引
号;但是#{}使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,
可以自动添加单引号。
3、#{}可以防止sql注入,${}不可以
4、如下方式即避免了${}的注入危险,也达到了拼接字符串的功能。
select * from t_user where username like "%"#{模糊}"%"
1、mapper接口的全类名和映射文件的命名空间(namespace)保持一致
2、mapper接口中方法的方法名和映射文件中编写SQL的标签的id属性保持一致
1、where标签会将将if条件最前方多余的and去掉 ,不能去掉条件最后多余的and
2、choose、when、 otherwise相当于if…else if…else
3、trim用于去掉或添加标签中的内容
常用属性:
prefix:在trim标签中的内容的前面添加某些内容
prefixOverrides:在trim标签中的内容的前面去掉某些内容
suffix:在trim标签中的内容的后面添加某些内容
suffixOverrides:在trim标签中的内容的后面去掉某些内容
<select id="getEmpListByMoreTJ" resultType="Emp">
select * from t_emp
<trim prefix="where" suffixOverrides="and">
<if test="ename != '' and ename != null">
ename = #{ename} and
if>
<if test="age != '' and age != null">
age = #{age} and
if>
<if test="sex != '' and sex != null">
sex = #{sex}
if>
trim>
select>
4、foreach标签,separator分隔符,index 是当前迭代的序号
<foreach collection="emps" item="emp" open="(" separator="," close=")" index="index">
#{emp.id}
foreach>
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties"/>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
settings>
<typeAliases>
<package name="entity.*"/>
typeAliases>
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">plugin>
plugins>
<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="mapper"/>
mappers>
configuration>
package mapper;
import entity.Dept;
import entity.Emp;
import org.apache.ibatis.annotations.Param;
public interface DeptAndEmpMapper {
Dept getAllEmpByDept(@Param("deptId") Integer deptId);
Emp getEmpDeptByEmpId(@Param("empId") Integer empId);
Emp getEmpDeptByTowStep(@Param("empId") Integer empId);
Dept getDeptById(@Param("deptId") Integer deptId);
}
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.DeptAndEmpMapper">
<resultMap id="empMap" type="entity.Emp">
<id column="id" property="id"/>
<result column="name" property="name"/>
resultMap>
<resultMap id="deptMap" type="entity.Dept">
<id property="deptId" column="dept_id" />
<result property="deptName" column="dept_name"/>
resultMap>
<resultMap id="empDeptMap" type="entity.Emp">
<id column="id" property="id"/>
<result column="name" property="name"/>
<association property="dept" resultMap="deptMap"/>
resultMap>
<select id="getEmpDeptByEmpId" parameterType="java.lang.Integer" resultMap="empDeptMap">
select * from emp e left join dept d on d.dept_id = e.dept_id where e. id = #{empId}
select>
<resultMap id="empByDeptMap" type="entity.Dept">
<id property="deptId" column="dept_id" />
<result property="deptName" column="dept_name"/>
<collection property="empList" resultMap="empMap" />
resultMap>
<select id="getAllEmpByDept" parameterType="java.lang.Integer" resultMap="empByDeptMap">
select * from dept d left join emp e on d.dept_id = e.dept_id where d.dept_id = #{deptId}
select>
<resultMap id="empDeptByTowStepMap" type="entity.Emp">
<id column="id" property="id"/>
<result column="name" property="name"/>
<association property="dept" fetchType="lazy" select="mapper.DeptAndEmpMapper.getDeptById" column="dept_id"/>
resultMap>
<select id="getEmpDeptByTowStep" parameterType="java.lang.Integer" resultMap="empDeptByTowStepMap">
select * from emp e where e.id = #{empId}
select>
<select id="getDeptById" parameterType="java.lang.Integer" resultMap="deptMap">
select * from dept e where e.dept_id = #{deptId}
select>
mapper>
public class DeptAndEmpTest {
private SqlSession getSqlSession() throws IOException {
//读取核心配置文件
InputStream resource = Resources.getResourceAsStream("mybatis_config.xml");
//创建SQLSession工厂类
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(resource);
//创建会话,并设置自动提交事务 true
return sqlSessionFactory.openSession(true);
}
@Test//3、一对多关系,对象中含有集合-
public void test01() throws IOException {
SqlSession sqlSession = getSqlSession();
DeptAndEmpMapper mapper = sqlSession.getMapper(DeptAndEmpMapper.class);
Dept allEmpByDept = mapper.getAllEmpByDept(1);
System.out.println(allEmpByDept);
}
@Test//2、一对一关系,对象中含有对象
public void test02() throws IOException {
SqlSession sqlSession = getSqlSession();
DeptAndEmpMapper mapper = sqlSession.getMapper(DeptAndEmpMapper.class);
Emp emp = mapper.getEmpDeptByEmpId(1);
System.out.println(emp);
}
@Test//1、分两次查询sql
public void test03() throws IOException {
SqlSession sqlSession = getSqlSession();
DeptAndEmpMapper mapper = sqlSession.getMapper(DeptAndEmpMapper.class);
Emp emp = mapper.getEmpDeptByTowStep(1);
System.out.println(emp.getName());
}
}
package mapper;
import entity.Student;
import org.apache.ibatis.annotations.Param;
public interface StudentMapper {
Student selectStudent(String id);
Student selectByName(String name);
//封装参数以param值为key存入map
Student selectByNameId(@Param("name") String name, @Param("id") String id);
Student selectByStudent(Student student);
int selectById(String id);
int insertAreaDict(@Param("name") String name);
}
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.StudentMapper">
<resultMap id="studentMap" type="entity.Student">
<id property="sId" column="s_id"/>
<result property="sName" column="s_name"/>
<result property="sBirth" column="s_birth"/>
<result property="sSex" column="s_sex"/>
resultMap>
<select id="selectStudent" resultType="entity.Student" parameterType="java.lang.String">
select * from student where s_id = #{id}
select>
<select id="selectById" resultType="java.lang.Integer">
select count(*) from student where s_id = #{id}
select>
<select id="selectByName" resultMap="studentMap" >
select * from student where s_name = '${value}'
select>
<select id="selectByNameId" resultMap="studentMap" >
select * from student where s_name = #{name} and s_id = #{id}
select>
<select id="selectByStudent" resultMap="studentMap" parameterType="entity.Student">
select * from student where s_name = #{SName} and s_id = #{sId}
select>
<insert id="insertAreaDict" useGeneratedKeys="true" keyProperty="UUID">
INSERT INTO mooc_area_dict_t (UUID,show_name) VALUES (null, #{name});
insert>
mapper>
public class MybatisStartTest {
@Test//#{}占位符
public void test01() throws IOException {
SqlSession sqlSession = getSqlSession();
//通过代理模式创建StudentMapper的代理实现类
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
int count = studentMapper.selectById("01");
System.out.println(count);
sqlSession.close();
}
@Test
public void test02() throws IOException {
SqlSession sqlSession = getSqlSession();
//通过代理模式创建StudentMapper的代理实现类
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student student = studentMapper.selectStudent("01");
System.out.println(student);
sqlSession.close();
}
@Test//${} 3.5版本需要value或者
public void test03() throws IOException {
SqlSession sqlSession = getSqlSession();
//通过代理模式创建StudentMapper的代理实现类
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student student = studentMapper.selectByName("王菊");
System.out.println(student);
sqlSession.close();
}
@Test//@Param设置参数键名
public void test04() throws IOException {
SqlSession sqlSession = getSqlSession();
//通过代理模式创建StudentMapper的代理实现类
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student student = studentMapper.selectByNameId("王菊","08");
System.out.println(student);
sqlSession.close();
}
@Test//参数是实体类型可以直接取属性值
public void test05() throws IOException {
SqlSession sqlSession = getSqlSession();
//通过代理模式创建StudentMapper的代理实现类
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student user = new Student();
user.setSName("王菊");
user.setSId("08");
Student student = studentMapper.selectByStudent(user);
System.out.println(student);
sqlSession.close();
}
@Test//插入数据,自动生成主键id
public void test06() throws IOException {
SqlSession sqlSession = getSqlSession();
//通过代理模式创建StudentMapper的代理实现类
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
studentMapper.insertAreaDict("上传");
sqlSession.close();
}
private SqlSession getSqlSession() throws IOException {
//读取核心配置文件
InputStream resource = Resources.getResourceAsStream("mybatis_config.xml");
//创建SQLSession工厂类
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(resource);
//创建会话,并设置自动提交事务 true
return sqlSessionFactory.openSession(true);
}
}
①添加依赖
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelperartifactId>
<version>5.2.0version>
dependency>
②配置分页插件
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">plugin>
plugins>
pageNum:当前页的页码
pageSize:每页显示的条数
list:分页之后的数据
navigatePages:导航分页的展示的页码数
@Test
public void testPage(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
//查询功能之前开启分页功能
Page<Object> page = PageHelper.startPage(5, 4);
List<Emp> list = mapper.selectByExample(null);
//查询功能之后可以获取分页相关的所有数据
PageInfo<Emp> pageInfo = new PageInfo<>(list, 5);
list.forEach(System.out::println);
System.out.println(pageInfo);
}
PageInfo{
pageNum=8, pageSize=4, size=2, startRow=29, endRow=30, total=30, pages=8,
list=Page{count=true, pageNum=8, pageSize=4, startRow=28, endRow=32, total=30,
pages=8, reasonable=false, pageSizeZero=false},
prePage=7, nextPage=0, isFirstPage=false, isLastPage=true, hasPreviousPage=true,
hasNextPage=false, navigatePages=5, navigateFirstPage4, navigateLastPage8,
navigatepageNums=[4, 5, 6, 7, 8]
}
pageNum:当前页的页码
pageSize:每页显示的条数
size:当前页显示的真实条数
total:总记录数
pages:总页数
prePage:上一页的页码
nextPage:下一页的页码
isFirstPage/isLastPage:是否为第一页/最后一页
hasPreviousPage/hasNextPage:是否存在上一页/下一页
navigatePages:导航分页展示的页码数
navigatepageNums:导航分页的页码,[1,2,3,4,5]