MyBatis知识点总结
什么是MyBatis?
- 它是一款半自动的ORM持久层框架,具有较高的SQL灵活性,支持高级映射(一对一,一对多),动态SQL,延迟加载和缓存等特性,但它的数据库无关性较低
- ORM(Object Relation Mapping)对象关系映射
- 对象:Java对象
- 关系:数据库中的关系模型
- 对象关系映射:Java对象和数据库的关系模型之间建立一种对用关系
- 比如用一个Java的Student类,去对应数据库中的一张student表,类中的属性和表中的列一一对应
- Student类就对应student表,一个Student对象就对应student表中的一行数据
- mybatis的特点
- mybatis是:半自动的ORM框架,需要手动编写SQL语句
- 全自动的ORM框架(如:hibernate),不需要编写SQL语句
- hibernate只需设置好ORM映射关系,就可以实现CRUD操作
- mybatis需要手写SQL,灵活性更高,但是换数据库时,需要重写SQL,因为mybatis的数据无关性低
- 相对于JDBC,它提供了输入映射和输出映射,方便sql的参数设置和结果集封装
- 提供了关联查询和动态SQL等功能,极大地提升了开发的效率
项目创建思路整理
项目结构
-
创建Maven项目
-
在pom.xml文件中导包
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.19</version> </dependency> </dependencies>
-
在Java目录下建包
- entity 实体类
- utils 工具类
- dao 数据操作对象
-
在resources目录下建mybatis-config.xml文件
项目搭建好,开始干活
-
编写实体类
- Student.java
- 成员变量与字段名尽量相同
-
连接数据库的准备
-
在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> <!--日志--> <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> <!--配置数据库操作环境--> <environments default="mysql"> <environment id="mysql"> <transactionManager type="JDBC"></transactionManager> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql:///stusys?serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="111111"/> </dataSource> </environment> </environments> <!--配置映射文件--> <mappers> <mapper resource="mapper/StudentMapper.xml"></mapper> <!-- <mapper class="com.dx.dao.StudentDao"></mapper>--> </mappers> </configuration>
-
-
写数据库连接的工具类
public class MyBatisUtil { static SqlSessionFactory factory=null; static { try { InputStream in = Resources.getResourceAsStream("mybatis-config.xml"); factory = new SqlSessionFactoryBuilder().build(in); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession(){ return factory.openSession(); } }
-
开始写DAO层(数据连接对象)
-
写StudentDao接口文件
public interface StudentDao { List<Student> select(); Student selectById(int id); int insert(Student student); int updata(Student student); int deleteById(int id); }
-
写映射文件StudentMapper.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 namespace="StudentMapper"> <select id="select" resultType="com.dx.entity.Student"> select * from student </select> <select id="selectById" parameterType="int" resultType="com.dx.entity.Student"> select * from student where id=#{id} </select> <insert id="insert" parameterType="com.dx.entity.Student"> insert into student(sname,age,gender,address,phone,remark) values(#{sname},#{age},#{gender},#{address},#{phone},#{remark}) </insert> <update id="updata" parameterType="com.dx.entity.Student"> update student set sname=#{sname},age=#{age},gender=#{gender},address=#{address},phone=#{phone},remark=#{remark} where id=#{id} </update> <delete id="deleteById"> delete from student where id = #{id} </delete> </mapper>
-
-
写实现类
public class StudentDaoImpl implements StudentDao { @Override public List<Student> select() { SqlSession sqlSession = MyBatisUtil.getSqlSession(); //传入的第一个参数为:mapper文件中的命名空间名称.sql语句id List<Student> students = sqlSession.selectList("StudentMapper.select"); sqlSession.close(); return students; } @Override public Student selectById(int id) { SqlSession sqlSession = MyBatisUtil.getSqlSession(); //传入的第二个参数为:查询条件,如果有多个查询条件应该封装成对象(对象的成员变量名要与sql的字段名保持一致)或使用map Student student = sqlSession.selectOne("StudentMapper.selectById",id); sqlSession.close(); return student; } @Override public int insert(Student student) { SqlSession sqlSession = MyBatisUtil.getSqlSession(); int result = sqlSession.insert("StudentMapper.insert", student); //增、删、改 都需要提交事务 //jdbc默认自动提交,MyBatis默认手动提交 sqlSession.commit(); sqlSession.close(); return result; } @Override public int updata(Student student) { SqlSession sqlSession = MyBatisUtil.getSqlSession(); int result = sqlSession.insert("StudentMapper.updata", student); //增、删、改 都需要提交事务 //jdbc默认自动提交,MyBatis默认手动提交 sqlSession.commit(); sqlSession.close(); return result; } @Override public int deleteById(int id) { SqlSession sqlSession = MyBatisUtil.getSqlSession(); int result = sqlSession.insert("StudentMapper.deleteById", id); //增、删、改 都需要提交事务 //jdbc默认自动提交,MyBatis默认手动提交 sqlSession.commit(); sqlSession.close(); return result; } }
-
写测试类
public class MyTest { @Test public void crudTest(){ StudentDaoImpl studentDao = new StudentDaoImpl(); //查 // List<Student> student = new StudentDaoImpl().select(); // Student student = studentDao.selectById(2); // System.out.println(student); //增 // Student student = new Student("莎莎", 22, "1", "zhegnzhou", "1242330", "iafg"); // int res = studentDao.insert(student); //改 // Student student = new Student(17, "shasha", 22, "1", "zhegnzhou", "1242330", "iafg"); // int res = studentDao.updata(student); //删 int res = studentDao.deleteById(17); if (res == 1) { System.out.println("成功"); } else { System.out.println("失败"); } } }
代理模式
dao接口+mapper文件
要求
- mapper文件中的命名空间必须与dao接口的全限定名保持一致
- mapper文件中的sql语句ID必须与dao接口中的方法名称保持一致
- mapper文件中parameterType传入参数类型必须与dao接口中的方法形参类型保持一致
- mapper文件中resultType传出结果类型必须与dao接口中的方法返回值“保持一致”
使用方法
-
不使用代理模式
SqlSession sqlSession = MybatisUtil.getSqlSession(); //两个参数(Mapper的命名空间名.sql标签的id , [传入的参数] ) Emp emp = sqlSession.selectOne("empNamespace.selectById", 7566); System.out.println(emp); sqlSession.close();
-
使用代理
SqlSession sqlSession = MybatisUtil.getSqlSession(); //获取Mapper代理对象 getMapper(接口.class) 返回值为当前指定接口的实现对象 DeptDao deptDao = sqlSession.getMapper(DeptDao.class); Dept dept = deptDao.selectById(10); System.out.println(dept); sqlSession.close();
mybatis配置文件
全局设置(日志和下划线转驼峰)
<settings>
<!--开启下划线转驼峰-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!--开启sql日志输出-->
<!-- <setting name="logImpl" value="org.apache.ibatis.logging.stdout.StdOutImpl"/>-->
<setting name="logImpl" value="LOG4J"/>
</settings>
设置别名
- 自带的
- int -> java.lang.Integer
- _int -> int
- double
- string->java.lang.String
- map -> java.util.Map,
- hashmap -> java.util.HashMap
- list -> java.util.List
- 自定义别名
<!--设置别名-->
<typeAliases>
<!--为单个文件设置别名-->
<typeAlias type="com.dx.entity.Emp" alias="emp"/>
<!--为包下的所有文件设置别名,自动生成两个别名:1.类名 2.类名(首字母小写)-->
<package name="com.dx.entity"/>
</typeAliases>
配置数据操作环境
<environments default="mysql">
<environment id="mysql">
<!--事务管理-->
<transactionManager type="JDBC"></transactionManager>
<!--数据源-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///student?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="111111"/>
</dataSource>
</environment>
<environment id="oracle">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:localhost:1521:orcl"/>
<property name="username" value="root"/>
<property name="password" value="111111"/>
</dataSource>
</environment>
</environments>
加载mapper映射文件
<mappers>
<!--在classpath下找mapper文件-->
<mapper resource="mapper/EmpMapper.xml"/>
<!--classpath下找指定的类-->
<mapper class="com.bjpowernode.dao.EmpDao"/>
<!--批量加载接口
1.sql使用注解式来提交mapper.xml文件
2.mapper文件与接口同名,同目录 -->
<package name="com.bjpowernode.dao"/>
</mappers>
log4j日志管理
日志配置文件
# 全局日志配置
log4j.rootLogger=DEBUG, stdout
# MyBatis 日志配置
#局部日志记录配置
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p %c.%M() --%m%n
### 输出DEBUG 级别以上的日志到=E://logs/error.log ###
log4j.appender.file = org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.File = D:/logs/test.log
#log4j.appender.file.Append = true
#log4j.appender.file.Threshold = DEBUG
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
### 输出DEBUG 级别以上的日志到=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
log4j的使用
/**
* java.util.logging.Logger(JUL)
*/
private Logger logger = Logger.getLogger(Log4jTest.class);
@Test
public void run(){
//错误信息
logger.error("error日志");
//警告信息
logger.warn("warn日志");
//普通信息
logger.info("info日志");
//调试信息
logger.debug("debug日志");
//底层信息
logger.trace("trace日志");
}
映射配置文件
结果映射
-
自动映射
<select id="selectAll" resultType="com.dx.entity.Emp"> select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp order by empno desc </select>
-
手动映射
<resultMap id="ResultMap" type="emp"> <!--设置主键字段与属性对应关系--> <id column="empno" property="empno"/> <!--设置普通字段与属性对应关系--> <result column="ename" property="ename"/> <result column="job" property="job"/> <result column="mgr" property="mgr"/> <result column="hiredate" property="hiredate"/> <result column="sal" property="sal"/> <result column="comm" property="comm"/> <result column="deptno" property="deptno"/> </resultMap> <select id="selectAll2" resultMap="ResultMap"> select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp order by empno desc </select>
占位符#与$
-
${}的sql是静态sql
-
#{}的sql是动态sql
-
<!-- #{}占位符,会预编译 1.传入参数为简单类型,占位符中的变量名称可以随意定义 2.传入参数为POJO类型,占位符中的变量名称必须与POJO属性名称保持一致 String sql = "select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp where empno=?"; ${}拼接符号, 会引起SQL注入的问题 1.传入参数为简单类型,拼接符号中的变量名称不可以随意定义,仅能为value 2.传入参数为POJO类型,拼接符号中的变量名称必须与POJO属性名称保持一致 String sql = "select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp where empno=" + value; --> <select id="selectById" parameterType="int" resultType="Emp"> select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp where empno=#{empno} </select> <select id="selectById2" parameterType="int" resultType="Emp"> select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp where empno=${value} </select>
模糊查询
<!--使用#{}时,这样写是不对的,需要用concat拼接
select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp where ename like '%#{name}%'-->
<!--方式一:使用concat拼接-->
<select id="selectByEname" parameterType="String" resultType="emp">
select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp where ename like concat('%',#{name},'%')
</select>
<!--方式二:使用${}拼接-->
<select id="selectByEname2" parameterType="String" resultType="emp">
select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp where ename like '%${value}%'
</select>
<!--方式三:使用<bind>标签-->
<select id="selectByEname3" parameterType="String" resultType="Emp">
<bind name="keyname" value="'%'+_parameter+'%'"/>
select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp where ename like #{keyname}
</select>
传入多参数
建议:参数为2-4个使用@Param,参数过多使用实体类或Map集合
传入参数为Map
-
mapper.xml
<!--传入参数为map集合,占位符的变量名就是map的key--> <select id="selectByParam" parameterType="map" resultType="emp"> select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp where deptno=#{aaa} and sal>=#{bbb} </select>
-
test.java
@Test public void selectByMap(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); EmpDao empDao = sqlSession.getMapper(EmpDao.class); HashMap<String, Object> map = new HashMap<>(); map.put("aaa",10); map.put("bbb",2000); List<Emp> emps = empDao.selectByParam(map); for (Emp emp : emps) { System.out.println(emp); } sqlSession.close(); }
使用@Param注解
-
mapper.xml
<select id="selectByParam2" parameterType="map" resultType="emp"> select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp where deptno=#{deptno} and sal>=#{sal} </select>
-
dao.java接口
public List<Emp> selectByParam2(@Param(value="deptno") Integer deptno,@Param("sal") Double sal);
-
test.java
@Test public void selectByMap2(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); EmpDao empDao = sqlSession.getMapper(EmpDao.class); List<Emp> emps = empDao.selectByParam2(10,3000.0); for (Emp emp : emps) { System.out.println(emp); } sqlSession.close(); }
分页查询
-
使用sql语句
<select id="selectPage" parameterType="map" resultType="emp"> select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp order by empno limit #{page},#{num} </select>
-
使用 RowBounds()
<select id="selectPage2" resultType="emp"> select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp order by empno </select>
public List<Emp> selectPage2(RowBounds rowBounds);
//使用RowBounds(起始坐标,展示条数)实现 RowBounds rowBounds = new RowBounds(10, 5); List<Emp> emps = empDao.selectPage2(rowBounds);
-
使用PageHelper插件
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.2.0</version> </dependency>
<plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins>
<select id="selectPage3" resultType="emp"> select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp order by empno </select>
//使用分页插件 PageHelper.startPage(当前页码,每页条数); PageHelper.startPage(1,5); List<Emp> emps = empDao.selectPage3(); //在PageHelper提供一个PageInfo的分页工具类 PageInfo<Emp> pageInfo = new PageInfo<>(list); pageInfo.getList(); System.out.println("当前页码:" + pageInfo.getPageNum()); System.out.println("每页条数:" + pageInfo.getPageSize()); System.out.println("总记录数:" + pageInfo.getTotal()); System.out.println("总页数:" + pageInfo.getPages()); System.out.println("上一页:" + pageInfo.getPrePage()); System.out.println("下一页:" + pageInfo.getNextPage()); System.out.println("是否有上一页:" + pageInfo.isHasPreviousPage()); System.out.println("是否有下一页:" + pageInfo.isHasNextPage()); System.out.println("是否为首页:" + pageInfo.isIsFirstPage()); System.out.println("是否为末页:" + pageInfo.isIsLastPage()); System.out.println("页码数组:" + Arrays.toString(pageInfo.getNavigatepageNums()));
插入数时返回主键值
-
<!-- 插入数据时,返回主键值(主键需要是自增长) useGeneratedKeys: 是否开启返回主键值功能,默认是关闭 keyColumn: 指定表中的主键字段,如果属性名和字段名相同可省略 keyProperty: 指定存主键值的实体对象属性名 --> <insert id="insert" parameterType="emp" useGeneratedKeys="true" keyColumn="empno" keyProperty="empno"> insert into emp(ename,job,mgr,hiredate,sal,comm,deptno) values (#{ename},#{job},#{mgr},#{hiredate},#{sal},#{comm},#{deptno}) </insert>
-
@Test public void insertTest() { SqlSession sqlSession = MybatisUtils.getSqlSession(); EmpDao empDao = sqlSession.getMapper(EmpDao.class); Emp emp = new Emp("小小", "经理", 100, new Date(), 5600.0, 1000.0, 20); System.out.println("数据插入前empno="+emp.getEmpno()); empDao.insert(emp); System.out.println("数据插入后empno="+emp.getEmpno()); sqlSession.commit(); sqlSession.close(); }
动态sql
-
if
<!--传入参数是实体类时,参数使用属性名--> <select id="selectUseIf" resultType="emp"> select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp where <if test="ename!=null and ename !='' "> ename like concat('%',#{ename},'%') </if> <if test="sal!=null"> and sal >= #{sal} </if> </select> <!--传入参数是简单类型时,mybatis标签(if、bind等标签)只能用 _parameter 代表传入的参数--> <select id="selectUseIf2" parameterType="String" resultType="emp"> select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp where <if test="_parameter!=null and _parameter !='' "> ename = #{ename} </if> </select>
-
where和choose
<select id="selectUseWhere" resultType="emp"> select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp <where> <if test="ename!=null and ename !='' "> ename like concat('%',#{ename},'%') </if> <if test="sal!=null"> and sal >= #{sal} </if> <!-- <choose>--> <!-- <when test=""></when>--> <!-- <when test=""></when>--> <!-- <when test=""></when>--> <!-- <otherwise></otherwise>--> <!-- </choose>--> </where> </select>
-
set
<update id="updateUseSet" parameterType="emp"> update emp <set> <if test="ename!=null"> ename=#{ename}, </if> <if test="job!=null"> job=#{job}, </if> </set> where empno=#{empno} </update>
-
foreach
<!--批量删除 Array --> <delete id="deleteUseForeach" parameterType="int"> delete from emp where empno in <foreach collection="array" open="(" close=")" separator="," item="id"> #{id} </foreach> </delete> <!--批量删除 list --> <delete id="deleteUseForeach2" parameterType="int"> delete from emp where empno in <foreach collection="list" open="(" close=")" separator="," item="id"> #{id} </foreach> </delete>
-
Trim
<!--Trim标签 insert into emp(ename,job,mgr,hiredate,sal,comm,deptno) values (#{ename},#{job},#{mgr},#{hiredate},#{sal},#{comm},#{deptno}) prefix:sql拼接的前缀 suffix:sql拼接的后缀 prefixOverrides:在拼接完成之后去除整个语句中指定前部 suffixOverrides:在拼接完成之后去除整个语句中指定后部 --> <insert id="insertUseTrim" parameterType="com.dx.entity.Emp"> insert into emp <trim prefix="(" suffix=")" suffixOverrides=","> <if test="ename!=null"> ename, </if> <if test="job!=null"> job, </if> <if test="mgr!=null"> mgr, </if> <if test="hiredate!=null"> hiredate, </if> <if test="sal!=null"> sal, </if> <if test="comm!=null"> comm, </if> <if test="deptno!=null"> deptno, </if> </trim> <trim prefix=" values (" suffix=")" suffixOverrides=","> <if test="ename!=null"> #{ename}, </if> <if test="job!=null"> #{job}, </if> <if test="mgr!=null"> #{mgr}, </if> <if test="hiredate!=null"> #{hiredate}, </if> <if test="sal!=null"> #{sal}, </if> <if test="comm!=null"> #{comm}, </if> <if test="deptno!=null"> #{deptno} </if> </trim> </insert>
-
测试类
@Test public void if_where_choose_Test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); EmpDao empDao = sqlSession.getMapper(EmpDao.class); Emp param = new Emp(); param.setEname("S"); param.setSal(1000.0); List<Emp> empList = empDao.selectUseIf(param); List<Emp> empList = empDao.selectUseWhere(param); for (Emp emp : empList) { System.out.println(emp); } sqlSession.close(); } @Test public void set_Test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); EmpDao empDao = sqlSession.getMapper(EmpDao.class); Emp param = new Emp(); param.setEmpno(666); param.setEname("shasha"); param.setJob("医生"); empDao.updateUseSet(param); System.out.println("插入成功!"); sqlSession.commit(); sqlSession.close(); } @Test public void foreachTest(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); EmpDao empDao = sqlSession.getMapper(EmpDao.class); //批量删除-数组 empDao.deleteUseForeach(new Integer[]{1,2,3,4}); //批量删除-集合 empDao.deleteUseForeach2(Arrays.asList(1,2,3,4,5,6)); sqlSession.commit(); System.out.println("删除成功"); sqlSession.close(); }
使用注解
使用lombok
-
导包
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.24</version> </dependency>
-
常用注解
- @Setter 注解在类或字段,注解在类时为所有字段生成setter方法,注解在字段上时只为该字段生成setter方法。
- @Getter 使用方法同上,区别在于生成的是getter方法。
- @ToString 注解在类,添加toString方法。
- @EqualsAndHashCode 注解在类,生成hashCode和equals方法。
- @NoArgsConstructor 注解在类,生成无参的构造方法。
- @RequiredArgsConstructor 注解在类,为类中需要特殊处理的字段生成构造方法,比如final和被@NonNull注解的字段。
- @AllArgsConstructor 注解在类,生成包含类中所有字段的构造方法。
- @Data 注解在类,生成setter/getter、equals、canEqual、hashCode、toString方法,如为final属性,则不会为该属性生成setter方法。
- @Slf4j 注解在类,生成log变量,严格意义来说是常量。private static final Logger log = LoggerFactory.getLogger(UserController.class);
Mybatis注解
-
@Select
-
@Insert
-
@Delete
-
@Update
-
简单的sql可以用,复杂的不推荐使用
-
用法
public interface UserMapper { @Insert("insert into user (name,pwd) value (#{name},#{pwd})") Integer insert(User user); @Delete("delete from user where id = #{id}") Integer delete(Integer id); @Select("select id,name,pwd from user ") List<User> selectAll(); /* 动态sql 写法 */ @Select("<script>select id,name,pwd from user <where> <if test='id != null'>id > 18</if> </where></script>") List<User> selectList(@Param("age") Integer age); }
缓存
一级缓存
-
一级缓存:在同一个sqlSession中
-
一级缓存是内存式缓存,必须使用,不能关闭
-
查询时,先查询一级缓存,如果没有找到数据再发送sql语句查询数据,并将结果放到sqlSession中
-
@Test public void firstCacheTest(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); System.out.println("——————————————————————————第一次查询——————————————————————————"); UserDao userDao = sqlSession.getMapper(UserDao.class); User user = userDao.selectUserById(2); System.out.println(user); //清空一级缓存 //sqlSession.commit(); System.out.println("——————————————————————————第二次查询——————————————————————————"); UserDao userDao2 = sqlSession.getMapper(UserDao.class); User user2 = userDao2.selectUserById(2); System.out.println(user2); System.out.println("——————————————————————————两次结果对比——————————————————————————"); System.out.println(user==user2); sqlSession.close(); }
二级缓存
-
二级缓存:在同一个SqlSessionFactory中
-
二级缓存有三个开关
- 第一个在mybatis-config.xml中设置cacheEnabled为true(默认开启)
- 第二个在mapper.xml中加上 (不加上就相当于关闭)
- 第三个在select标签中配置 useCache=“true” (默认开启)
-
被缓存的数据需要支持序列化,所以存储的对象必须实现可序列化接口
-
@Test public void secondCacheTest(){ System.out.println("——————————————————————————第一次查询——————————————————————————"); SqlSession sqlSession = MybatisUtils.getSqlSession(); UserDao userDao = sqlSession.getMapper(UserDao.class); User user = userDao.selectUserById(2); System.out.println(user); sqlSession.close(); System.out.println("——————————————————————————第二次查询——————————————————————————"); SqlSession sqlSession2 = MybatisUtils.getSqlSession(); UserDao userDao2 = sqlSession2.getMapper(UserDao.class); User user2 = userDao2.selectUserById(2); System.out.println(user2); sqlSession2.close(); System.out.println("——————————————————————————两次结果对比——————————————————————————"); System.out.println(user==user2); }
联表查询⭐
使用的数据库
- student表
id | sname | cid |
---|---|---|
1 | 小李 | 1 |
2 | 小陈 | 2 |
3 | 小郭 | 2 |
4 | 小夏 | 1 |
- classes表
id | cname |
---|---|
1 | 一班 |
2 | 二班 |
3 | 三班 |
一对一
-
查询学生和其所在的班级
-
//Dao接口 List<Student> selectStudentAndClasses();
-
<!--**************************** 简单使用一对多 *********************************--> <resultMap id="selectResultMap" type="com.dx.entity.Student"> <!--主键字段--> <id column="id" property="id"/> <!--普通字段--> <result column="sname" property="sname"/> <result column="cid" property="cid"/> <!--一对一、多对一 关系映射--> <association property="classes" javaType="com.dx.entity.Classes"> <id column="id" property="id"/> <result column="cname" property="cname"/> </association> </resultMap> <select id="selectStudentAndClasses" resultMap="selectResultMap"> select s.id,s.sname,s.cid,c.cname from student s join classes c on s.cid=c.id </select>
-
扩展:使用 代码块 和 继承
<!--**************************** 扩展知识 *********************************--> <!--使用继承,将父标签配置全部继承到子标签中--> <resultMap id="BaseResultMap" type="com.dx.entity.Student"> <id column="id" property="id"/> <result column="sname" property="sname"/> <result column="cid" property="cid"/> </resultMap> <resultMap id="selectResultMap2" type="com.dx.entity.Student" extends="BaseResultMap"> <association property="classes" javaType="com.dx.entity.Classes"> <id column="id" property="id"/> <result column="cname" property="cname"/> </association> </resultMap> <!--使用sql片段--> <sql id="FeildList"> s.id,s.sname,s.cid,c.cname </sql> <select id="selectStudentAndClasses2" resultMap="selectResultMap"> select <include refid="FeildList"></include> from student s join classes c on s.cid=c.id </select>
一对多
-
查询某个班级里的学生
-
Classes selectById(Integer id);
-
<resultMap id="BaseResultMap" type="com.dx.entity.Classes"> <id column="id" property="id"/> <result column="cname" property="cname"/> </resultMap> <resultMap id="selectByIdResultMap" type="com.dx.entity.Classes" extends="BaseResultMap"> <collection property="studentList" ofType="com.dx.entity.Student"> <id column="sid" property="id"/> <result column="sname" property="sname"/> </collection> </resultMap> <select id="selectById" resultMap="selectByIdResultMap"> select c.id,c.cname,s.id sid,s.sname from classes c left join student s on c.id=s.cid where c.id=#{id} </select>
关联查询
-
Dao接口
Classes selectOne(Integer id);
-
StudentMapper.xml
<!--********* 用于ClassesMapper.xml中的关联查询 *********--> <select id="selectByCid" resultType="com.dx.entity.Student"> select id,sname from student where cid=#{cid} </select>
-
ClassesMapper.xml
<!--************************ 关联查询 ************************--> <resultMap id="SelectOneResultMap" type="com.dx.entity.Classes" extends="BaseResultMap"> <!-- column:传递到关联查询中的数据字段名称 select:表示关联数据到什么地方查询 --> <collection property="studentList" ofType="com.dx.entity.Student" column="id" select="com.dx.dao.StudentDao.selectByCid"> </collection> </resultMap> <select id="selectOne" parameterType="int" resultMap="SelectOneResultMap"> select id,cname from classes where id=#{id} </select>