持久层技术解决方案
# 持久层技术解决方案
- Jdbc 技术
- Spring 的 jdbcTemplate spring 对 jdbc 的简单封装
- apache 的 DBUtils
-- 以上这些都不是框架
-- jdbc 是规范
-- template 和 dbutils 是工具类
什么是 ORM
# ORM Object Relational Mappging 对象关系映射
- 就是把数据表和实体类、数据列和实体属性对应起来
- 让我们只操作实体类、就可以实现对数据表的操作
-
MyBatis 中的设计模式
# 创建工厂 mybatis 使用了建造者模式 builder 就是构建者
# 生产 sqlSession 使用了工厂模式
# 创建 dao 接口的实现类使用了动态代理 --> 代理模式
自定义 MyBatis
mybatis 和 jdbc 的对应关系
# mybatis 和 jdbc 的对应关系
< dataSource type = " POOLED" >
< property name = " driver" value = " com.mysql.jdbc.Driver" />
< property name = " url" value = " jdbc:mysql:///data?characterEncoding=utf-8" />
< property name = " username" value = " root" />
< property name = " password" value = " 123" />
</ dataSource>
# 主配置文件中的上述信息 可以创建出 Connection 连接对象
< mappers>
< mapper resource = " mapper/userMapper.xml" />
</ mappers>
# 主配置文件中的上述信息 可以 找到 mapper 层实体类对应的 xml
< mapper namespace = " cn.liuweiwei.mapper.UserMapper" >
< select id = " findAll" resultType = " cn.liuweiwei.domain.User" >
select id, username, password from user
</ select>
</ mapper>
# 对应的 xml mapper 标签中的 namespace 就是要代理的实体类的全限定类名
# 得到全限定类名、可以通过反射创建 UserMapper 的代理对象
< select id = " findAll" resultType = " cn.liuweiwei.domain.User" >
select id, username, password from user
</ select>
# select 标签表示查询 id表示要代理的方法名 标签中的内容为要执行的 sql 语句
# 上述信息可以对应 connection.properctedStatement(String sql);
# select 标签中的 resultType 对应 jdbc 中的 ResultSet 结果集
# resultType属性的值就是结果集中要封装对象的全限定名
# 通过反射创建要封装的对象、通过表中的字段调用对象的setXXX (XXX表示表中的字段名)方法封装结果集
# 遍历结果集、将封装的对象添加到List集合中、完成查询
# 所以 select 标签中的 resultType/resultMap 不能省略 !!即使是简单数据类型也不能省略!!
Mybatis 模糊查询
select * from user where username link "%" #{username} "%"
插入数据之后、获取插入数据的id
< insert id = " insertOne" >
< selectKey keyProperty = " id" keyColumn = " id" resultType = " int" order = " AFTER" >
select last_insert_id();
</ selectKey>
insert into user(username, password) values(#{username}, #{password});
</ insert>
parameterType 扩展
< select id = " findOne" parameterType = " vo" >
select id, username, password where id = #{user.id}
</ select>
public class VO {
private User user;
public User getUser ( ) {
return user;
}
public void setUser ( User user) {
this . user = user;
}
}
PreparedStatement 对象的执行方法
execute
# execute()
- 他能执行crud中的任意语句、返回值为boolean类型、表示是否有结果集
# executeUpdate()
- 只能执行cud、查询语句无法执行、他的返回值是影响数据库记录的行数
# executeQuery()
- 只能执行select语句、无法执行增删改、返回值是封装的 resultSet 对象
主配置文件中的properties
< properties resource = " jdbc.properties" > </ properties>
- resource 类路径下的资源文件
- url 统一资源定位符
url 和 uri 的区别
# url 统一资源定位符: http://localhost:8080/web/helloServlet
# uri 统一资源标识符:(应用内资源定位符)/web/helloServlet
# url = 协议 + 主机 + 端口 + uri;
连接池
# 连接池就是一个存储连接的容器
# 容器就是一个线程安全的集合对象、该集合还必须实现队列的特性(先进先出)
Mybatis 中的连接池
# MyBatis 连接池提供了三种方式的配置
- 配置的位置:主配置文件中的 datasource 标签、type 属性就是表示采用的连接方式
- type 属性的 取值:
- POOLED: 采用传统的 javax.sql.DataSource 的规范中的连接池、mybatis 中有对此规范的实现
- UNPOOLED:采用传统的获取连接的方式、虽然也实现 DataSource 接口、但是并没有使用池的思想
- JNDI:采用服务器提供的 JNDI 技术实现 来获取DataSource 对象、不同服务的实现是不一样的
-- JNDI 连接池、如果不是 web 项目 或者 maven 的 war 项目、是不能使用的
-- tomcat 中的连接池是 dbcp 连接池
# JNDI: Java Naming and Directory Interface
# 是 sun 公司推出的一套规范、目的是为了模仿Windows中的注册表、在服务器中注册数据源
MyBatis 中的延迟加载
# 应用场景:
- 在一对多中、当我们有一个用户、他有100个账户、在查询用户的时候、要不要把关联的账户查出来?
- 在查询账户的时候、要不要把关联的用户查出来?
# 延迟加载
- 在真正使用数据的时候发起查询、不用的时候就不查询、按需加载(懒加载)
# 立即加载
- 不管用不用、只要一调用方法、立即查询所有
# 在对应的四钟表关系中:一对一、一对多、多对一、多对多
- 一对一、多对一:通常采用立即加载
- 一对多、多对多:通常采用延迟加载
在主配置文件中全局开启延迟加载
< settings>
< setting name = " lazyLoadingEnabled" value = " true" />
</ settings>
MyBatis 中的缓存
# 什么是缓存?
- 存在于内存中的临时数据
# 为什么使用缓存
- 减少和数据库的交互次数、提升执行效率
# 什么样的数据能使用缓存?
- 经常查询并且不经常改变的
- 数据的正确与否对最终的结果影响不大的
MyBatis 中的一级缓存
# 一级缓存:
- 指的是MyBatis中 sqlsession 对象的缓存
- 当我们执行查询之后、查询的结果会同时存入到SqlSession 为我们提供的一块区域中
- 该区域的结构是一个 Map、当我们再次查询同样的数据的时候、MyBatis 先去从 sqlSession 中
- 查询是否有缓存、有的话直接拿出来用、当sqlsession 对象 close 后、mybatis 的一级缓存也就清空了
- sqlSession 的 clearCache() 方法也可以清空一级缓存
# MyBatis 的一级缓存是默认开启的
# 触发清空一级缓存的情况
- 执行增删改都会清空一级缓存
- 调用 SqlSession 的 commit() 也会清空一级缓存
MyBatis 的二级缓存
# 二级缓存
- 他指的是MyBatis 中 SqlSessionFactory 对象的缓存、
- 由同一个 SqlSessionFactory 对象创建的 SqlSession 共享其缓存
# 二级缓存的使用步骤
- 让 MyBatis 框架支持二级缓存(在主配置文件中配置)
- 让当前的映射文件支持二级缓存(在userMapper.xml 中配置)
- 让当前的操作支持二级缓存(在 select 标签中配置)
# 二级缓存中存放的是序列化后的数据(字符串)而不是对象
- 比如 {"id": "1", "username": "vivi", "age": "19"} 字符串
- 在sqlsession击中缓存时会被反序列化成一个**新的对象**
- 这样做是为了解决多个 sqlsession 都操作同一个对象引起数据安全问题
开启二级缓存
< settings>
< setting name = " cacheEnabled" value = " true" />
</ settings>
< mapper namespace = " cn.liuweiwei.mapper.UserMapper" >
< cache />
< select id = " findAll" resultType = " cn.liuweiwei.domain.User" useCache = " true" >
select id, username, password
from user
</ select>
</ mapper>