1,JNDI数据源
2,Mybatis 延迟加载策略
3,Mybatis 缓存
4,Mybatis 注解开发
JNDI数据源
JNDI:Java Naming and Directory Interface。是SUN公司推出的一套规范,属于JavaEE技术之一。目的是模仿windows系统中的注册表。
JNDI数据源的使用案例:
1,创建Maven的war工程并导入坐标
2,项目结构如下:
<?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>
<%@ 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>
</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
Mybatis 延迟加载策略
延迟加载:
就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载
好处:
先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快
坏处 :
因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降
<!--配置参数-->
<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>
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>
Mybatis 缓存
什么是缓存?
存在于内存中的临时数据
为什么使用缓存?
减少和数据库的交互次数,提高执行效率
什么情况下使用缓存?
适用于缓存:
经常查询且不经常改变的
数据的正确与否对最终的结果影响不大的
不适用于缓存:
经常改变的数据
数据的正确与否对最终的结果影响很大的(商品库存,银行的汇率)
Mybatis 中缓存分为一级缓存,二级缓存
它指的是Mybatis中SqlSession对象的缓存,当我们执行查询之后,查询的结果回同时存入到SqlSession为我们提供的一块区域中,该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去SqlSession中查询是否有,有的话直接拿出来用。当SqlSession对象消失时,mybatis的一级缓存也就消失了
一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flush 或 close,它就存在
一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存
它指的时Mybatis中SqlSessionFactory对象的缓存,由同一个SqlSessionFactory对象创建的SqlSession共享其缓存
二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的
二级缓存的使用步骤:
①,第一步:在 mybatis-config.xml 中开启二级缓存
<settings>
<!-- 开启二级缓存的支持 -->
<setting name="cacheEnabled" value="true"/>
</settings>
②,第二步:配置相关的 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 映射文件中的标签中设置
useCache="true"
代表当前这个 statement 要使用二级缓存,如果不使用二级缓存可以设置为 false。
注意:针对每次查询都需要最新的数据 sql,要设置成 useCache=false,禁用二级缓存。当我们在使用二级缓存时,所缓存的类一定要实现 java.io.Serializable 接口,这种就可以使用序列化方式来保存对象。
Mybatis 注解开发
@Insert
:实现新增
@Update
:实现更新
@Delete
:实现删除
@Select
:实现查询
@Result
:实现结果集封装
@Results
:可以与@Result
一起使用,封装多个结果集
@ResultMap
:实现引用@Results
定义的封装
@One
:实现一对一结果集封装
@Many
:实现一对多结果集封装
@SelectProvider
: 实现动态 SQL 映射
@CacheNamespace
:实现注解二级缓存的使用
@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);
实现复杂关系映射之前我们可以在映射文件中通过配置来实现,在使用注解开发时我们需要借助@Results
注解,@Result
注解,@One
注解,@Many
注解。
复杂关系映射的注解说明:
@Results
注解代替的是标签
该注解中可以使用单个@Result
注解,也可以使用@Result
集合@Results({@Result(),@Result()})或@Results(@Result())
@Resutl
注解代替了
标签和
标签
@Result
中 属性介绍:
id
是否是主键字段
column
数据库的列名
property
需要装配的属性名
one 需要使用的@One
注解(@Result(one=@One)()))
many 需要使用的@Many
注解(@Result(many=@many)()))
@One
注解(一对一),代替了
标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
@One
注解属性介绍:
select
指定用的 来多表查询的 sqlmapper
fetchType
会覆盖全局的配置参数 lazyLoadingEnabled
,LAZY(延迟加载), EAGER(立即加载)
使用格式:@Result(column=" ",property="",one=@One(select=""))
@Many
注解(多对一),代替了
标签, 是多表查询的关键,在注解中用来指定子查询返回对象集合。
注意:聚集元素用来处理“一对多”的关系。需要指定映射的 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);
<!-- 配置二级缓存 -->
<settings>
<!-- 开启二级缓存的支持 -->
<setting name="cacheEnabled" value="true"/>
</settings>
@CacheNamespace(blocking=true)//mybatis 基于注解方式实现配置二级缓存
public interface IUserDao {
}
下一章,(11)MyBatisPlus————条件构造器,AR,代码生成器以及插件扩展