1,JNDI数据源
2,Mybatis 延迟加载策略
2.1,何为延迟加载?2.2,使用 assocation 实现延迟加载2.3,使用 Collection 实现延迟加载3,Mybatis 缓存
3.1,Mybatis 一级缓存3.2,Mybatis 二级缓存4,Mybatis 注解开发
4.1,mybatis 的常用注解说明4.2,使用 Mybatis 注解实现基本 CRUD4.3,使用注解实现复杂关系映射开发4.4,mybatis 基于注解的二级缓存JNDI:Java Naming and Directory Interface。是SUN公司推出的一套规范,属于JavaEE技术之一。目的是模仿windows系统中的注册表。
JNDI数据源的使用案例:
1,创建Maven的war工程并导入坐标 2,项目结构如下:
示例代码如下:context.xml文件: <?xml version="1.0" encoding="UTF-8"?> <Context> <!-- <Resource name="jdbc/test" 数据源的名称 type="javax.sql.DataSource" 数据源类型 auth="Container" 数据源提供者 maxActive="20" 最大活动数 maxWait="10000" 最大等待时间 maxIdle="5" 最大空闲数 username="root" 用户名 password="root" 密码 driverClassName="com.mysql.jdbc.Driver" 驱动类 url="jdbc:mysql://localhost:3306/test" 连接url字符串 /> --> <Resource name="jdbc/test" type="javax.sql.DataSource" auth="Container" maxActive="20" maxWait="10000" maxIdle="5" username="root" password="root" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/test" /> </Context> index.jsp页面 <%@ page import="org.apache.ibatis.io.Resources" %> <%@ page import="org.apache.ibatis.session.SqlSession" %> <%@ page import="org.apache.ibatis.session.SqlSessionFactory" %> <%@ page import="org.apache.ibatis.session.SqlSessionFactoryBuilder" %> <%@ page import="zhou.dao.IUserDao" %> <%@ page import="zhou.entity.User" %> <%@ page import="java.io.InputStream" %> <%@ page import="java.util.List" %> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <body> <h2>Hello World!</h2> <% //1.读取配置文件 InputStream in = Resources.getResourceAsStream("mybatis-config.xml"); //2.根据配置文件构建SqlSessionFactory SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(in); //3.使用SqlSessionFactory创建SqlSession对象 SqlSession sqlSession = factory.openSession(); //4.使用SqlSession构建Dao的代理对象 IUserDao userDao = sqlSession.getMapper(IUserDao.class); //5.执行dao中的findAll方法 List<User> users = userDao.findAll(); for(User user : users){ System.out.println(user); } //6.释放资源 sqlSession.close(); in.close(); %> </body> </html> pom.xml </properties> <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.4.5</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2</version> </dependency> </dependencies> <build> <finalName>JndiDemo</finalName> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.2.2</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> </plugins> </pluginManagement> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> </resources> </build> </project>延迟加载:
就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载
好处:
先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快
坏处 :
因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降
2,使用 assocation 实现延迟加载 修改配置文件,再mybatis-config.xml配置文件中添加: <!--配置参数--> <settings> <!--开启Mybatis支持延迟加载--> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"></setting> </settings> 账户的持久层映射文件: <!-- 定义封装account和user的resultMap --> <resultMap id="accountUserMaps" type="account"> <id property="id" column="id"></id> <result property="uid" column="uid"></result> <result property="money" column="money"></result> <!-- 一对一的关系映射:配置封装user的内容 select属性指定的内容:查询用户的唯一标识: column属性指定的内容:用户根据id查询时,所需要的参数的值 --> <association property="user" column="uid" javaType="user" select="com.zhou.dao.IUserDao.findById"></association> </resultMap> <!-- 查询所有 --> <select id="findAll" resultMap="accountUserMaps"> select * from account </select> 用户的持久层映射文件: <?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.zhou.dao.IUserDao"> <!-- 根据 id 查询 --> <select id="findById" resultType="user" parameterType="int" > select * from user where id = #{uid} </select> </mapper> 3,使用 Collection 实现延迟加载 User 实体类: public class User implements Serializable { private Integer id; private String username; private Date birthday; private String sex; private String address; } 编写用户和账户持久层接口的方法: /** * 查询所有用户,同时获取出每个用户下的所有账户信息 */ List<User> findAll(); /** * 根据用户 id 查询账户信息 */ List<Account> findByUid(Integer uid); 编写用户持久层映射 配置: <resultMap type="user" id="userMap"> <id column="id" property="id"></id> <result column="username" property="username"/> <result column="address" property="address"/> <result column="sex" property="sex"/> <result column="birthday" property="birthday"/> <!-- collection 是用于建立一对多中集合属性的对应关系 ofType 用于指定集合元素的数据类型 select 是用于指定查询账户的唯一标识(账户的 dao 全限定类名加上方法名称) column 是用于指定使用哪个字段的值作为条件查询 --> <collection property="accounts" ofType="account" select="com.zhou.dao.IAccountDao.findByUid" column="id"> </collection> </resultMap> <!-- 配置查询所有操作 --> <select id="findAll" resultMap="userMap"> select * from user </select> 标签 :主要用于加载关联的集合对象select 属性 :用于指定查询 account 列表的 sql 语句,所以填写的是该 sql 映射的 idcolumn 属性 :用于指定 select 属性的 sql 语句的参数来源,上面的参数来自于 user 的 id 列,所以就写成 id 这一个字段名了什么是缓存?
存在于内存中的临时数据
为什么使用缓存?
减少和数据库的交互次数,提高执行效率
什么情况下使用缓存?
适用于缓存:
经常查询且不经常改变的 数据的正确与否对最终的结果影响不大的
不适用于缓存:
经常改变的数据 数据的正确与否对最终的结果影响很大的(商品库存,银行的汇率)
Mybatis 中缓存分为一级缓存,二级缓存
1,Mybatis 一级缓存它指的是Mybatis中SqlSession对象的缓存,当我们执行查询之后,查询的结果回同时存入到SqlSession为我们提供的一块区域中,该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去SqlSession中查询是否有,有的话直接拿出来用。当SqlSession对象消失时,mybatis的一级缓存也就消失了
一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flush 或 close,它就存在
一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存
2,Mybatis 二级缓存它指的时Mybatis中SqlSessionFactory对象的缓存,由同一个SqlSessionFactory对象创建的SqlSession共享其缓存
二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的
二级缓存结构图:
二级缓存的使用步骤:
①,第一步:在 mybatis-config.xml 中开启二级缓存
<settings> <!-- 开启二级缓存的支持 --> <setting name="cacheEnabled" value="true"/> </settings> 因为 cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为false 代表不开启二级缓存。②,第二步:配置相关的 Mapper 映射文件
<!-- <cache>标签表示当前这个 mapper 映射将使用二级缓存,区分的标准就看 mapper 的 namespace 值。--> <?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.zhou.dao.IUserDao"> <!-- 开启二级缓存的支持 --> <cache></cache> </mapper>③, 第三步:配置 statement 上面的 useCache 属性
<!-- 根据 id 查询 --> <select id="findById" resultType="user" parameterType="int" useCache="true"> select * from user where id = #{uid} </select>将 UserDao.xml 映射文件中的<select>标签中设置 useCache="true"代表当前这个 statement 要使用二级缓存,如果不使用二级缓存可以设置为 false。
注意:针对每次查询都需要最新的数据 sql,要设置成 useCache=false,禁用二级缓存。当我们在使用二级缓存时,所缓存的类一定要实现 java.io.Serializable 接口,这种就可以使用序列化方式来保存对象。
@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与@Result 一起使用,封装多个结果集
@ResultMap:实现引用@Results 定义的封装
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
@SelectProvider: 实现动态 SQL 映射
@CacheNamespace:实现注解二级缓存的使用
2,使用 Mybatis 注解实现基本 CRUD 查询操作: @Select("select * from user") @Results(id="userMap", value= { @Result(id=true,column="id",property="id"), @Result(column="username",property="username"), @Result(column="sex",property="sex"), @Result(column="address",property="address"), @Result(column="birthday",property="birthday") }) List<User> findAll(); /** * 根据 id 查询一个用户 */ @Select("select * from user where id = #{uid} ") @ResultMap("userMap") User queryUserById(Integer userId); /** * 查询使用聚合函数 */ @Select("select count(*) from user ") int findTotal(); /** * 模糊查询 */ @Select("select * from user where username like #{username} ") List<User> findByName(String name); 保存操作: /** * 保存操作 */ @Insert("insert into user(username,sex,birthday,address)values(#{username},#{sex},#{birthday},#{address})") @SelectKey(keyColumn="id",keyProperty="id",resultType=Integer.class,before = false, statement = { "select last_insert_id()" }) int saveUser(User user); 更新操作: /** * 更新操作 */ @Update("update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id =#{id} ") int updateUser(User user); 删除操作: /** * 删除用户 */ @Delete("delete from user where id = #{uid} ") int deleteUser(Integer userId); 3,使用注解实现复杂关系映射开发实现复杂关系映射之前我们可以在映射文件中通过配置来实现,在使用注解开发时我们需要借助@Results 注解,@Result 注解,@One 注解,@Many 注解。
复杂关系映射的注解说明:
@Results 注解代替的是标签<resultMap>该注解中可以使用单个@Result 注解,也可以使用@Result 集合@Results({@Result(),@Result()})或@Results(@Result())
@Resutl 注解代替了 <id> 标签和<result> 标签
@Result 中 属性介绍:
id 是否是主键字段
column 数据库的列名
property 需要装配的属性名
one 需要使用的@One 注解(@Result(one=@One)()))
many 需要使用的@Many 注解(@Result(many=@many)()))
@One 注解(一对一),代替了<assocation> 标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
@One 注解属性介绍:
select 指定用的 来多表查询的 sqlmapper
fetchType 会覆盖全局的配置参数 lazyLoadingEnabled,LAZY(延迟加载), EAGER(立即加载)
使用格式:@Result(column=" ",property="",one=@One(select=""))
@Many 注解(多对一),代替了<Collection> 标签, 是多表查询的关键,在注解中用来指定子查询返回对象集合。
注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType(一般为 ArrayList)但是注解中可以不定义;
使用格式:@Result(property="",column="",many=@Many(select=""))
使用 注解 实现一对一 复杂关系映射 及延迟加载的示例代码:
/** * 查询所有账户,采用延迟加载的方式查询账户的所属用户 */ @Select("select * from account") @Results(id="accountMap", value= { @Result(id=true,column="id",property="id"), @Result(column="uid",property="uid"), @Result(column="money",property="money"), @Result(column="uid", property="user", one=@One(select="com.zhou.dao.IUserDao.findById", fetchType= FetchType.LAZY) ) }) List<Account> findAll(); @Select("select * from user where id = #{uid} ") @ResultMap("userMap") User findById(Integer userId); 使用 注解 实现一对多复杂关系映射示例代码: /** * 查询所有用户 */ @Select("select * from user") @Results(id="userMap", value= { @Result(id=true,column="id",property="id"), @Result(column="username",property="username"), @Result(column="sex",property="sex"), @Result(column="address",property="address"), @Result(column="birthday",property="birthday"), @Result(column="id",property="accounts", many=@Many( select="com.zhou.dao.AccountDao.findByUid", fetchType= FetchType.LAZY ) ) }) List<User> findAll(); @Select("select * from account where uid = #{uid} ") List<Account> findByUid(Integer userId); 4,mybatis 基于注解的二级缓存 在 mybatis-config.xml 中开启二级缓存支持: <!-- 配置二级缓存 --> <settings> <!-- 开启二级缓存的支持 --> <setting name="cacheEnabled" value="true"/> </settings> 在持久层接口中使用注解配置二级缓存: @CacheNamespace(blocking=true)//mybatis 基于注解方式实现配置二级缓存 public interface IUserDao {}下一章,(11)MyBatisPlus————条件构造器,AR,代码生成器以及插件扩展