java web 43 : MyBatis框架 ( ... / 接口+xml / 接口+注解、缓存 )
接口开发
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"> <!-- MyBatis的全局配置文件 --> <configuration> <!-- 1.配置环境,可配置多个环境(比如:develop开发、test测试) --> <environments default="develop"> <environment id="develop"> <!-- 1.1.配置事务管理方式:JDBC/MANAGED JDBC:将事务交给JDBC管理(推荐) MANAGED:自己管理事务 --> <transactionManager type="JDBC"></transactionManager> <!-- 1.2.配置数据源,即连接池 JNDI/POOLED/UNPOOLED JNDI:已过时 POOLED:使用连接池(推荐) UNPOOLED:不使用连接池 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/yonghedb?characterEncoding=utf-8" /> <property name="username" value="root" /> <property name="password" value="root" /> </dataSource> </environment> </environments> <!-- 2.导入Mapper配置文件,如果mapper文件有多个,可以通过多个mapper标签导入 --> <mappers> <mapper resource="EmpMapper.xml" /> </mappers> </configuration>
EmpMapper.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="com.tedu.dao.EmpMapper"> <!-- 练习5:查询emp表中指定id的员工信息 --> <select id="findById05" resultType="com.tedu.pojo.Emp"> select * from emp where id=#{id} <!-- 占位符,内部不能为空 --> </select> <!-- 练习6:新增员工信息 --> <insert id="insert06"> insert into emp value(null,#{name},#{job},#{salary}) </insert> <!-- --> <update id="update07"> update emp set job=#{job},salary=#{salary} where name=#{name} </update> </mapper>
com.tedu.pojo/Emp.java
package com.tedu.pojo; /** * 封装员工信息的实体类(POJO) */ public class Emp { /*声明4个变量,用于封装员工信息 * 尽量让Emp类中的变量名和emp表中的列名保持一致 * */ private Integer id; private String name; private String job; private Double salary; //提供对应的get和set方法 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getJob() { return job; } public void setJob(String job) { this.job = job; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } @Override public String toString() { return "Emp [id=" + id + ", name=" + name + ", job=" + job + ", salary=" + salary + "]"; } //提供toString(方便打印) }
com.tedu.dao/EmpMapper.java(接口)
package com.tedu.dao; import java.util.List; import java.util.Map; import com.tedu.pojo.Emp; /* * 全类名=包名+接口名 * com.tedu.dao.EmpMapper 等于 * EmpMapper.xml文件中的namespace名 */ /* * 框架提供实现类 */ public interface EmpMapper { public List<Emp> findAll(); public Emp findById05(Integer id); public void insert06(Map map); public void insert06(Emp emp); public void update07(Emp emp); }
com.tedu/TestMybatis04.java
package com.tedu; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Before; import org.junit.Test; import com.tedu.dao.EmpMapper; import com.tedu.pojo.Emp; public class TestMybatis04 { SqlSession session = null; /*被@Before标记的方法,在每一个@Test方法执行之前都会执行*/ @Before public void testBefore() throws IOException { //1.读取mybatis的核心配置文件(mybatis-config.xml) 源码根目录的xml文件编译后会输出到classes目录下 InputStream in = Resources.getResourceAsStream("mybatis-config.xml"); //2.基于上面读取的配置信息获取一个SqlSessionFactory对象 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(in); //3.基于SqlSessionFactory对象获取一个SqlSession对象 session = factory.openSession(true); //true:设置自动提交事务,每次执行一条sql之后都会自动提交 } /*********************************************/ /** MyBatis的接口开发 **/ /*********************************************/ /* * 1.写一个接口,接口的全类名等于对应Mapper文件的namespace值 * 2.接口中的方法名要对应Mapper文件中SQL标签的id值 * 3.如果是查询,select标签上的resultType类型要和接口中方法的 * 返回值类型保持一致;(但,如果接口方法返回List<泛型>集合), * 4.接口中的方法的参数类型 和SQL标签上的参数类型(可以不指定)保持一致! */ @Test public void testFindAll01() { //获取EmpMapper接口的子类对象(框架负责创建) EmpMapper mapper = session.getMapper(EmpMapper.class); //调用接口子类对象中的方法,查询数据库 List<Emp> list = mapper.findAll(); for(Emp emp:list) { System.out.println(emp); } } @Test public void testFindById05() { EmpMapper mapper = session.getMapper(EmpMapper.class); Emp emp = mapper.findById05(6); System.out.println(emp); } @Test public void testInsert() { EmpMapper mapper = session.getMapper(EmpMapper.class); Emp emp = new Emp(); emp.setName("张飞"); emp.setJob("JAVA开发"); emp.setSalary(16000.0); mapper.insert06(emp); } @Test public void testUpdate() { EmpMapper mapper = session.getMapper(EmpMapper.class); Emp emp = new Emp(); emp.setName("张飞"); emp.setJob("前端"); emp.setSalary(27000.1); mapper.update07(emp); } }
*********************************************************************************
接口 + 注解开发
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"> <!-- MyBatis的全局配置文件 --> <configuration> <!-- 0.引入jdbc.properties --> <properties resource="jdbc.properties"/> <!-- 1.配置环境,可配置多个环境(比如:develop开发、test测试) --> <environments default="develop"> <environment id="develop"> <!-- 1.1.配置事务管理方式:JDBC/MANAGED JDBC:将事务交给JDBC管理(推荐) MANAGED:自己管理事务 --> <transactionManager type="JDBC"></transactionManager> <!-- 1.2.配置数据源,即连接池 JNDI/POOLED/UNPOOLED JNDI:已过时 POOLED:使用连接池(推荐) UNPOOLED:不使用连接池 --> <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> <!-- 2.导入Mapper配置文件,如果mapper文件有多个,可以通过多个mapper标签导入 --> <mappers> <!-- SQL语句已经提取到EmpMapper接口中,这里不再需要导入xml文件。指定EmpMapper接口所在的包即可--> <!-- <mapper resource="EmpMapper.xml" /> --> <package name="com.tedu.dao"/> </mappers> </configuration>
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/yonghedb?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
com.tedu.pojo/Emp.java
package com.tedu.pojo; /** * 封装员工信息的实体类(POJO) */ public class Emp { /*声明4个变量,用于封装员工信息 * 尽量让Emp类中的变量名和emp表中的列名保持一致 * */ private Integer id; private String name; private String job; private Double salary; //提供对应的get和set方法 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getJob() { return job; } public void setJob(String job) { this.job = job; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } @Override public String toString() { return "Emp [id=" + id + ", name=" + name + ", job=" + job + ", salary=" + salary + "]"; } //提供toString(方便打印) }
com.tedu.dao/EmpMapper.java(接口)
package com.tedu.dao; import java.util.List; import java.util.Map; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import com.tedu.pojo.Emp; /* * 全类名=包名+接口名 * com.tedu.dao.EmpMapper 等于 * EmpMapper.xml文件中的namespace名 */ /* * 框架提供实现类 */ public interface EmpMapper { //注解开发 @Select("select * from emp") public List<Emp> findAll(); @Select("select * from emp where id=#{id}") public Emp findById05(Integer id); //@Insert("insert into emp value(null,#{name},#{job},#{salary})") //public void insert06(Map map); @Insert("insert into emp value(null,#{name},#{job},#{salary})") public void insert06(Emp emp); @Update("update emp set job=#{job},salary=#{salary} where name=#{name}") public void update07(Emp emp); }
com.tedu/TestMybatis04.java
package com.tedu; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Before; import org.junit.Test; import com.tedu.dao.EmpMapper; import com.tedu.pojo.Emp; public class TestMybatis04 { SqlSession session = null; /*被@Before标记的方法,在每一个@Test方法执行之前都会执行*/ @Before public void testBefore() throws IOException { //1.读取mybatis的核心配置文件(mybatis-config.xml) 源码根目录的xml文件编译后会输出到classes目录下 InputStream in = Resources.getResourceAsStream("mybatis-config.xml"); //2.基于上面读取的配置信息获取一个SqlSessionFactory对象 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(in); //3.基于SqlSessionFactory对象获取一个SqlSession对象 session = factory.openSession(true); //true:设置自动提交事务,每次执行一条sql之后都会自动提交 } /*********************************************/ /** MyBatis的接口开发 **/ /*********************************************/ /* * 1.写一个接口,接口的全类名等于对应Mapper文件的namespace值 * 2.接口中的方法名要对应Mapper文件中SQL标签的id值 * 3.如果是查询,select标签上的resultType类型要和接口中方法的 * 返回值类型保持一致;(但,如果接口方法返回List<泛型>集合), * 4.接口中的方法的参数类型 和SQL标签上的参数类型(可以不指定)保持一致! */ @Test public void testFindAll01() { //获取EmpMapper接口的子类对象(框架负责创建) EmpMapper mapper = session.getMapper(EmpMapper.class); //调用接口子类对象中的方法,查询数据库 List<Emp> list = mapper.findAll(); for(Emp emp:list) { System.out.println(emp); } } @Test public void testFindById05() { EmpMapper mapper = session.getMapper(EmpMapper.class); Emp emp = mapper.findById05(6); System.out.println(emp); } @Test public void testInsert() { EmpMapper mapper = session.getMapper(EmpMapper.class); Emp emp = new Emp(); emp.setName("张飞"); emp.setJob("JAVA开发"); emp.setSalary(16000.0); mapper.insert06(emp); } @Test public void testUpdate() { EmpMapper mapper = session.getMapper(EmpMapper.class); Emp emp = new Emp(); emp.setName("张飞"); emp.setJob("后端"); emp.setSalary(27000.1); mapper.update07(emp); } }
*********************************************************************************
https://mybatis.org/mybatis-3/zh/sqlmap-xml.html#cache
一次查询的结果暂时存在内存中,再次查询相同数据的时候就可以直接从内存取数据,无需连接数据库,避免浪费资源,适用于经常查询并且不频繁改变的数据。
* 映射语句文件中所有select语句的结果将会被缓存
* 映射语句文件中所有insert、update和delete语句会刷新缓存
* 缓存会使用最近最少使用算法(LRU)来清除不需要的缓存
* 缓存不会定时进行刷新(即无刷新间隔)
* 缓存会保存列表或对象(无论查询方法返回哪种)的1024个引用
* 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改而不干扰其他调用者或线程所做的潜在修改
缓存失效的情况:
* 查询不同的内容
* 增删改操作
* 查询不同的Mapper.xml
* SqlSession对象调用 clearCache() 清理缓存
一级缓存默认开启,也叫本地会话缓存
二级缓存也叫全局缓存,作用域广,需要手动开启和配置,基于namespace,一个 namespace 对应一个二级缓存
* 只要开启了二级缓存,在同一个Mapper下就有效
* 所有的数据都会先放在一级缓存中,只有当会话提交或者关闭的时候才会提交到二级缓存中
开启二级缓存的步骤:
1.添加标签
<settings> <!-- 显示开启全局缓存 --> <setting name="cacheEnabled" value="true"> </settings>
2.在要使用二级缓存的Mapper.xml中添加<cache/>标签,例如
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true" />
先查询二级缓存,再查询一级缓存,最后查数据库