py-16-MyBatis

目录:

01: MyBatis基础CRUD操作

02: 接口实现

03: 动态排序、日志配置、缓存配置

04 :  高级映射、延迟加载、动态SQL


 01: MyBatis基础CRUD操作    

框架(Framework)

MyBatis

1.    MyBatis 简介                                                                                                            2

1.1.    MyBatis 概述?                                                                                              2

1.1.1.    MyBatis 是什么?                                                                              2

1.1.2.    MyBatis 应用场景                                                                              2

1.1.3.    MyBatis 应用优势                                                                              3

1.2.    MyBatis 架构体系?                                                                                      3

1.2.4.    MyBatis接口应用层                                                                           3

1.2.5.    MyBatis数据处理层                                                                           4

1.2.6.    MyBatis基础服务层                                                                           4

1.3.    MyBatis 核心组件?                                                                                      4

1.3.7.    MyBatis核心文件                                                                               4

1.3.8.    MyBatis 核心API                                                                                4

2.    MyBatis 编程基础                                                                                                    5

2.4.    MyBatis 基本步骤                                                                                        5

2.4.9.    JDBC 编程步骤回顾                                                                         5

2.4.10.    MyBaits 编程步骤分析                                                                    5

2.5.    MyBatis 编程实现                                                                                        6

2.5.11.    数据库数据准备                                                                              6

2.5.12.    创建Maven桌面项目                                                                       6

2.5.13.    添加配置及映射文件                                                                      7

2.5.14.    编写代码执行查询测试                                                                  9

3.    MyBatis 编程进阶                                                                                                  12

3.6.    MyBatis基于接口实现的基本步骤                                                           12

3.7.    MyBatis进阶编程实现                                                                               13

3.7.15.    创建Maven桌面项目                                                                     13

3.7.16.    创建config.properties文件                                                               13

3.7.17.    创建mybatis核心配置文件                                                            14

3.7.18.    创建Blog实体对象                                                                         14

3.7.19.    创建BlogDao接口                                                                          15

3.7.20.    创建BlogMapper映射文件                                                             16

3.7.21.    创建单元测试类执行测试                                                            17

3.8.    MyBatis业务增强                                                                                       19

3.8.22.    动态排序策略                                                                                19

3.8.23.    ID应用策略                                                                                    20

4.    MyBatis 高级应用                                                                                                  21

4.9.    日志配置应用                                                                                            21

4.9.24.    日志基本概述                                                                                21

4.9.25.    日志基本实现                                                                                22

4.10.    缓存配置应用                                                                                          23

4.10.26.    缓存基本概述                                                                              23

4.10.27.    缓存基本实现                                                                              23

4.11.    高级映射应用                                                                                          25

4.11.28.    高级映射基本概述                                                                       25

4.11.29.    高级映射基本实现                                                                       26

4.12.    延迟加载应用                                                                                         28

4.12.30.    延迟加载基本概述                                                                       28

4.12.31.    延迟加载基本实现                                                                       28

4.13.    动态SQL应用                                                                                         29

4.13.32.    动态SQL基本概述                                                                       29

4.13.33.    动态SQL基本实现                                                                      30

5.    总结                                                                                                                31

5.14.    重点和难点分析                                                                                     31

5.15.    常见FAQ                                                                                               31

5.16.    作业                                                                                                      32


01:MyBatis基础CRUD操作

1.MyBatis 简介

1.MyBatis 概述?

1.MyBatis 是什么?

MyBatis 由apache的ibatis演变而来,可以从如下几个方面加强理解与应用。

  1. 软件框架(Framework): 用于解决软件中的通用型(共性)问题

  2. 软件中的优秀的持久层框架(数据访问层):用于更好解决数据持久化问题

课后了解:JAVA生态项目中常用的持久层框架

hibernate (ORM 框架) :用于解决数据的持久化问题(数据库操作)


2.MyBatis 应用场景

MyBatis主要应用于Java技术生态项目的研发。例如:

  1. Java传统桌面型项目(例如传统的计费系统等)

  2. Java web 互联网项目(例如电商项目,企业互联网业务系统)


 3.MyBatis 应用优势

思考:

  1. 互联网项目的硬性要求是什么?(快速交付)

  2. 互联网项目的如何进行技术选型?

第一:稳定,可靠,性能;

第二:学习成本。

第三:是否可持续发展,社区支持的力度)

思考:

传统JDBC开发劣势?

  1. 编程步骤,参数配置及读取相关繁琐(配置信息的读取,都需要自己写代码)

  2. 数据直接映射硬编码的强度会比较高(代码冗余相对较高,维护起来困难)

  3. 数据关系映射的实现相对困难?(one2one,one2many,many2many)

思考:框架MyBatis开发优势

  1. 封装了JDBC共性,简化了代码的编写,提高了代码的开发速度,以及可维护性。

  2. 合理的架构设计,提高了系统的稳定性,访问性能,可扩展性。

框架MyBatis开发劣势

  1. SQL语句编写的工作量相对较大。(相对hibernate框架)

  2. SQL语句依赖于数据库,移植性相对较差。(不是最大劣势)


 2.MyBatis 架构体系?

对于任何一个持久层框架,都应该具备接口服务,数据处理服务,基础服务等相关功能,MyBatis也不例外,它会具体如下几个层结构.


 4.MyBatis接口应用层

MyBatis接口应用层主要负责对外提供应用服务,例如

  1. 数据查询

  2. 数据修改

  3. 数据删除

  4. 数据插入


5.MyBatis数据处理层

MyBatis数据处理层主要负责处理数据访问问题

  1. SQL参数映射(Dao方法参数与映射文件中#{}表达式映射)

  2. SQL解析(语法,语义) 例如: select * from blog where id=#{id}

  3. SQL 执行(将sql发送到数据库端执行)

  4. SQL 结果映射(例如将ResultSet中的数据存到map)

  5. ....


 6.MyBatis基础服务层

MyBatis基础服务层主要负责提供如下几个方面的服务:

  1. 连接服务 (配置连接池,)

  2. 事务服务(保证数据的原子性,一致性,隔离性,一致性。)

  3. 缓存服务(更好的提高查询性能)

  4. 配置服务 (别名配置,映射配置,...,日志配置,....)

  5. .....


 3.MyBatis 核心组件?

7.MyBatis核心文件

MyBatis 核心应用组件:

  1. 配置文件(提供基础配置信息,例如连接配置,缓存配置,映射配置)

  2. 映射文件(定义SQL映射)


8.MyBatis 核心API

MyBatis 项目中核心API:

  1. SqlSessionFactoryBuilder (负责读取配置文件,创建SqlSessionFactory对象)

  2. SqlSessionFactory(负责创建SqlSession对象)

  3. SqlSession(负责连接的维护,事务的处理,类似JDBC中的Connection)

  4. .....

思考:

1)核心组件在应用中的一个角色定位?

2)应用底层会用到哪些设计模式?建造模式,工厂模式


 2.MyBatis 编程基础

4.MyBatis 基本步骤

9.JDBC 编程步骤回顾

JDBC 编程的基本步骤如下:

  1. 加载驱动程序Driver (Class.forName(“com.mysql.jdbc.Driver”))

  2. 建立连接Connection (DriverManager.getConnection(url,username,password))

  3. 创建Statement (conn.createStatement())

  4. 发送sql (stmt.executeUpdate(sql))

  5. 处理结果ResultSet (while(rs.next))

  6. 释放资源(close)


10.MyBaits 编程步骤分析

MyBatis 项目中一般的编程步骤:

Step01:创建maven 桌面项目(Java 项目)

Step02:添加mybatis依赖(pom.xml)以及mysql驱动依赖

Step03:创建mybatis 配置文件,映射文件

Step04:配置数据访问(配置文件),SQL映射(映射文件)

Step05:创建MyBatis API(例如SqlSession)对象,执行SQL操作.

思考?

  1. 数据库连不上,可能存在哪些问题?

        a.检测url,用户名,密码

        b.检测端口号(port)

        c.id地址是否能ping 通

        d.检测驱动程序(有可能依赖的驱动程序与数据库版本不兼容)

  2.mybatis 配置文件的名字有要求吗?(只要符合标识符规范即可)

  3.mybatis 配置文件是要对哪些信息进行配置呢?

  4.mybatis 映射文件中主要用于定义哪些内容?(sql元素)

 5.MyBatis 执行SQL操作时的一个基本过程是怎样的?

        a.step01:MyBatis API调用JDBC API

        b.step02:JDBC API 调用数据库驱动程序API


 5.MyBatis 编程实现

11.数据库数据准备

创建数据库,并在库中创建表

create database cgbmybatis character set utf8;

打开数据库

use cgbmybatis

创建表

create table blog(
id int primary key auto_increment,
title varchar(200) not null,
content varchar(500) not null,
createdTime date
) engine=innoDB;

向表中写入数据

insert into blog values (null,'ta','ta...',now());
insert into blog values (null,'tb','tb...',now());

12.创建Maven桌面项目

创建maven 桌面项目,并添加依赖(mybatis,mysql驱动)

说明:桌面项目的创建参考doc.tedu.cn中maven配置

添加mybatis依赖

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.8</version>
</dependency>

添加MySQL驱动依赖

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>

添加junit依赖

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>

思考:

  1. 添加依赖时注意groupId的选择?(选正规的)

  2. 添加依赖以后pom.xml文件假如有错什么原因?

         检测网络,检测maven配置(setting.xml)


 13.添加配置及映射文件

在src/main/resources目录下创建配置文件mybatis-configs.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 核心配置文件(配置mybatis基础信息:例如连接,映射文件,...) -->
<configuration>
<properties resource="config.properties"></properties>

<settings>
<!-- 启用log4j日志库 -->
<setting name="logImpl" value="log4j" />
<!-- 配置一级缓存:本地缓存作用域 -->
<setting name="localCacheScope" value="SESSION" />
<!-- 配置二级缓存:缓存启用 -->
<setting name="cacheEnabled" value="true" />
<!-- 配置全局延迟加载;lazyLoadingEnabled:延迟加载启用 -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 设置按需加载(配合上面的延迟加载属性实现;aggressiveLazyLoading积极的延迟加载) -->
<setting name="aggressiveLazyLoading" value="false" />
</settings>
<!-- 别名配置 -->
<typeAliases>
<!-- 为指定包中的所有类创建别名,别名默认为类名,但首字母小写。 -->
<package name="com.jt.entity" />
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<!-- 映射路径 -->
<mappers>
<mapper resource="mapper/AuthorMapper.xml" />
<mapper resource="mapper/BlogAuthorMapper.xml" />
</mappers>
</configuration>

说明:

1)配置文件的头可从官方文档进行拷贝.

2)配置文件元素没有提示是什么原因? 对应的dtd文件取不到

提示信息的配置请参考:http://schema.tedu.cn/proxy/

step02:在src/main/resources/mapper目录下创建映射文件BlogMapper.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.jt.blog.BlogDao">
</mapper>

说明:

  1. 映射文件的命名空间用于约束元素id的唯一性.

  2. 映射文件的格式最好是包结构形式

  3. 映射文件内部可以定义很多元素,每个元素必须有一个唯一id,例如select

在mapper文件中添加如下元素:

查询所有blog数据

<select id="findBlogs" resultType="map">
select * from blog
</select>
public static void main(String[] args) throws IOException {

//初始化SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder()
.build(Resources.getResourceAsStream("mybatis-configs.xml"));
//1.创建SqlSession对象(相当于创建一个连接)
SqlSession session = factory.openSession();
//2.执行查询操作(selectList("命名空间"+"元素id"))
List<Map<String,Object>> list = session.selectList("com.jt.blog.BlogDao.findBlogs");

System.out.println(list);
//3.释放资源(类似关闭连接)
session.close();
}

根据id查询blog数据

<select id="findBlogById" resultType="map">
select *
from blog
where id=#{id}
</select>

使用jdbc的方式查询,用结果集元数据进行分析

@Test
public void testFindBlogById01() throws ClassNotFoundException, Exception {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.建立连接
String url = "jdbc:mysql:///cgbmybatis";
Connection conn = DriverManager.getConnection(url,"root","root");
//System.out.println(123);

String sql = "select * from blog where id=?";
//3.创建statement
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1,1);
//4.执行查询
ResultSet rs = ps.executeQuery();
//获取结果集中的元数据
ResultSetMetaData md = rs.getMetaData();
//获取列计算
int cCount  = md.getColumnCount();
System.out.println(cCount);
Map<String,Object> map = null;
while(rs.next()) {
map = new HashMap<String,Object>();
for(int i=1;i<=cCount;i++) {
map.put(md.getColumnName(i), rs.getObject(i));
}
}
//5.处理结果(将取出的记录映射到map对象)
System.out.println(map);
//释放资源
conn.close();
ps.close();
rs.close();
}
/**
* 根据id查询blog数据,使用MyBatis框架
* @throws IOException
*/
@Test
public void TestFindBlogById02() throws IOException {
//初始化SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder()
.build(Resources.getResourceAsReader("mybatis-configs.xml"));
//1.创建SqlSession对象(相当于创建一个连接)
SqlSession session =  factory.openSession();
//2.执行查询操作(selectList("命名空间"+"元素id"))
Map<String,Object> map = session.selectOne("com.jt.blog.BlogDao.findBlogById", 1);
System.out.println(map);
//3.释放资源(类似关闭连接)
session.close();
}

限制查询blog元素(此方式参数的传递应用Object[]数组进行封装)

<select id="findPageBlogs"
resultType="map">
select *
from blog
limit #{array[0]},#{array[1]}
</select>
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
factory = new SqlSessionFactoryBuilder()
.build(Resources.getResourceAsStream("mybatis-configs.xml"));
}

@Test
public void findPageBlogs() {
SqlSession session = factory.openSession();
List<Map<String,Object>> list = session.selectList(
"com.jt.blog.BlogDao.findPageBlogs", new Object[] {1,2});
System.out.println(list);
session.close();
}

限制查询Blog元素(此方式的参数应用map进行封装,#{}表达式中的内容为map中的key)

<select id="findPageBlogs"
resultType="map">
select *
from blog
limit #{startIndex},#{pageSize}
</select>
/**
* 测试分页查询方法(传递Map的方式)
*/
@Test
public void findPageBlogs2() {
SqlSession session = factory.openSession();
Map<String,Integer> map = new  HashMap<String, Integer>();
map.put("startIndex", 1);
map.put("pageSize", 2);
List<Map<String,Object>>list = session.selectList("com.jt.blog.BlogDao.findPageBlogs2", map);


System.out.println(list);
session.close();
}

向表中插入数据元素定义

方案1:(测试时参数数据可以为Object[]类型数组)

<insert id="insertBlog02" >
insert into blog
(id,title,content,createdTime)
values
(null,#{array[0]},#{array[1]},#{array[2]})

</insert>
/**
* 插入数据,使用Object数组
*/
@Test
public void insertBlog02() {
SqlSession session = factory.openSession();
Object obj = new Object[]{"title2","content2",new Date()};
int n = session.insert("com.jt.blog.BlogDao.insertBlog02",obj);
System.out.println("插入了"+n+"数据");
session.commit();
}

方案2:(测试时参数数据可以为Blog类型对象或Map对象)

<insert id="insertBlog01" parameterType="com.jt.entity.Blog">
insert into blog
(id,title,content,createdTime)
values
(null,#{title},#{content},#{createdTime})

</insert>
/**
* 插入数据,使用实体类
*/
@Test
public void insertBlog01() {
SqlSession session = factory.openSession();
Blog blog = new Blog();
blog.setTitle("title1");
blog.setContent("content1");
blog.setCreatedTime(new Date());          
int n = session.insert("com.jt.blog.BlogDao.insertBlog", blog);
System.out.println("插入了"+n+"数据");
session.commit();

}

修改表中数据元素定义

方案1:(测试时参数传递需要为Object[]类型的数组)

<update id="updateObject">
update blog 
set title=#{array[0]},
content=#{array[1]}
where id=#{array[2]}
</update>
@Test
public void UpdateBlog01() {
SqlSession session = factory.openSession(true);
Object obj = new Object[] {"t_ta1","c_ta1",1};
int n = session.update("com.jt.blog.BlogDao.UpdateBlog01", obj);
System.out.println("更新了"+n+"数据");
}

方案2 (测试时参数传递可以是map或者blog对象)

<update id="UpdateBlog02">
update blog
set title=#{title},content=#{content}
where id=#{id}
</update>
/**
* 修改数据,Map传参
*
*/
@Test
public void UpdateBlog02() {
SqlSession session = factory.openSession(true);
Map<String,Object> map = new HashMap<String, Object>();
map.put("id", 2);
map.put("title", "t_ta2");
map.put("content", "c_ta2");
int n = session.update("com.jt.blog.BlogDao.UpdateBlog02", map);
System.out.println("更新了"+n+"数据");
session.commit();
}

删除表中元素元素定义

<delete id="deleteObject">
delete
from blog
where id=#{id}
</delete>
/**      
* 删除数据      
*/     
@Test    
public void deleteBlog() {           
SqlSession session = factory.openSession();          
int n = session.update("com.jt.blog.BlogDao.deleteBlog",1);          
System.out.println("删除了"+n+"数据");         
session.commit();   
}

14.编写代码执行查询测试

基于BlogMapper.xml文件中元素的定义,添加测试类及相关方法.

编写测试类并添加测试方法

public class TestBlog01 {
private SqlSessionFactory factory;
}

测试类中添加初始化factory的方法

@Before
public void init()throws IOException{
//初始化SqlSessionFactory
factory=new SqlSessionFactoryBuilder()
.build(Resources.getResourceAsStream(
"mybatis-configs.xml"));
}

测试类中添加查询所有blogs的方法

@Test
public void testFindBlogs(){
//1.创建SqlSession对象(相当于创建一个连接)
SqlSession session=factory.openSession();
//2.执行查询操作(selectList("命名空间"+"元素id"))
List<Object> list=session.selectList(
"com.jt.blog.BlogDao.findBlogs");
for(Object o:list){
System.out.println(o);
}
//3.释放资源(类似关闭连接)
session.close();
}

测试类中添加根据id执行查询方法

@Test
public void testFindBlogById(){
//1.创建session对象
SqlSession session=
factory.openSession();
//2.执行sql操作
String statement="com.jt.blog.BlogDao.findBlogById";
Map<String,Object> map=
session.selectOne(statement,1);
System.out.println(map);
//3.释放资源(关闭session对象)
session.close();
}

测试类中添加分页查询方法

@Test
public void testFindPageBlogs(){
//1.创建session对象
SqlSession session=
factory.openSession();
//2.执行sql操作?????
String statement="com.jt.blog.BlogDao.findPageBlogs";
Object parameter=new Object[]{0,4};
List<Map<?,?>> list=
session.selectList(statement, parameter);
for(Map<?,?>map:list){
System.out.println(map);
}
//3.释放资源(关闭session对象)
session.close();
};

测试类中添加插入数据的方法

@Test
public void testInsertObject(){
//1.创建session
SqlSession session=factory.openSession();
//2.执行sql
String statement="com.jt.blog.BlogDao.insertObject";
Object parameter=new Object[]{"te","te..."};
int rows=session.insert(statement, parameter);
System.out.println("insert.rows="+rows);
session.commit();
//3.关闭session
session.close();
}

测试类中添加修改方法

@Test
public void testUpdateObject(){
//1.创建session
SqlSession session=factory.openSession();
//2.执行sql
String statement="com.jt.blog.BlogDao.updateObject";
Object parameter=new Object[]{"taa","taa...",1};
int rows=session.update(statement, parameter);
System.out.println("update.rows="+rows);
session.commit();
//3.关闭session
session.close();
}

测试类中添加删除方法

@Test
public void testDeleteObject(){
//1.创建session
SqlSession session=factory.openSession();
//2.执行sql
String statement="com.jt.blog.BlogDao.deleteObject";
Object parameter=7;
int rows=session.delete(statement, parameter);
session.commit();
System.out.println("delete.rows="+rows);
//3.关闭session
session.close();

02: 接口实现、

3.MyBatis 编程进阶

本小节中会从mybatis编程的另一个角度(例如基于接口方式等)实现对数据库中数据的操作.


6.MyBatis基于接口实现的基本步骤

Step01: 创建maven桌面项目并添加依赖

Step02: 创建配置文件config.propertis(内容为数据库相关)

该文件寻贴主得

 Step03: 创建mybatis核心配置文件mybatis-configs.xml文件

该文件寻贴主得

Step04: 配置Mybatis基础数据服务(properties,datasource,mapper)

Step05: 创建mapper/BlogMapper.xml

该文件寻贴主得

 Step06: 创建实体类com.jt.entity.Blog(与表对应,可用于封装表中数据)

该文件寻贴主得

 Step07: 创建com.jt.dao.BlogDao接口,并添加相关方法.

Step08: 配置BlogMapper映射文件,添加相关元素.

Step09: 基于BlogDao接口与映射文件实现CRUD操作


7.MyBatis进阶编程实现

15.创建Maven桌面项目

创建maven桌面项目并添加依赖

<!-- 添加mybatis依赖 -->

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.8</version>
</dependency>

 <!-- 添加mysql驱动依赖 -->

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>

  <!-- 添加junit依赖 -->

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>

16.创建config.properties文件

在src/main/resource目录下创建config.properties文件,此文件中定义

系统中的一些常用配置信息,例如访问数据库的相关信息,其内容如下

driver=com.mysql.jdbc.Driver
url=jdbc:mysql:///cgbmybatis
username=root
password=root

17.创建mybatis核心配置文件

在src/main/resources目录下创建mybatis-configs.xml文件,并配置数据源等相关信息,数据信息从config.properties文件读取.

<?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>
<!--配置properties文件-->
<properties resource="config.properties"/>
<!-- 别名配置 -->
<typeAliases>

<!--
<typeAlias type="com.jt.entity.Blog" alias="blog"/>
-->
<!-- 为指定包中的所有类创建别名,别名默认为类名,但首字母小写。 -->
<package name="com.jt.entity"/>
</typeAliases>
<!-- 配置初始化环境(连接) -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url"  value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- 映射文件 -->
<mappers>
<mapper resource="mapper/BlogMapper.xml"/>
</mappers>
</configuration>

映射文件

<?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.jt.dao.BlogDao">
<select id="findBlogById"
parameterType="int"
resultType="blog">
select *
from blog
where id=#{id}
</select>
</mapper>

 18.创建Blog实体对象

创建com.jt.entity.Blog类实现与数据库中Blog表实现映射.

public class Blog {
private Integer id;
private String title;
private String content;
private Date createdTime;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Date getCreatedTime() {
return createdTime;
}
public void setCreatedTime(Date createdTime) {
this.createdTime = createdTime;
}
@Override
public String toString() {
return "Blog [id=" + id + ", title=" + title + ", content=" + content + ", createdTime=" + createdTime + "]";
}
}

19.创建BlogDao接口

创建com.jt.dao.BlogDao数据访问接口,并添加相关方法

package com.jt.dao;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.jt.entity.Blog;
public interface BlogDao {
/***
* 根据id进行对象查找
* @param id
* @return
*/
Blog findBlogById(Integer id);
List<Blog> findPageBlogs(
@Param("offset")Integer offset,
@Param("pageSize")Integer pageSize);
int insertObject(Blog blog);
int updateObject(Blog blog);
int deleteObject(Integer id);
}

20.创建BlogMapper映射文件

<?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.jt.dao.BlogDao">
</mapper>

BlogMapper文件中添加与BlogDao接口对应的映射元素

添加基于ID进行查询的元素

<select id="findBlogById"
parameterType="int"
resultType="blog">
select *
from blog
where id=#{id}
</select>

添加分页查询元素

<select id="findPageBlogs"
resultType="blog">
select *
from blog
limit #{offset},#{pageSize}
</select>

添加insert元素

<insert id="insertObject"
parameterType="blog">
insert into blog
(id,title,content,createdTime)
values
(null,#{title},#{content},now())
</insert>

添加更新元素

<update id="updateObject"
parameterType="blog">
update blog
set title=#{title},content=#{content}
where id=#{id}
</update>

添加删除元素

<delete id="deleteObject"
parameterType="int">
delete from blog where id=#{id}
</delete>

最后在mybatis-configs.xml中添加BlogMapper文件


21.创建单元测试类执行测试

创建单元测试类,并添加相关方法实现基于Dao接口方式的数据库操作.

package test;
import java.io.IOException;
import java.util.Date;
import java.util.List;
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.jt.dao.BlogDao;
import com.jt.entity.Blog;
public class TestBlog {

private SqlSessionFactory factory;
@Before
public void init() throws IOException {
factory = new SqlSessionFactoryBuilder()
.build(Resources.getResourceAsStream("mybatis-configs.xml"));
}

/**
* 基于id进行Blog信息的查询
* @param id
* @return
*/
@Test
public void TestFindBlogById() {
SqlSession session = factory.openSession();
//2.执行sql
//2.1获取dao对象
BlogDao dao =
session.getMapper(BlogDao.class);
//2.2执行dao中方法
Blog blog=dao.findBlogById(4);
System.out.println(blog);
//3.关闭session
session.close();
}

/**
* 分页拆查询
* @param offset
* @param pageSize
* @return
*/
@Test
public void TestFindPageBlogs() {
SqlSession session = factory.openSession();
BlogDao dao = session.getMapper(BlogDao.class);
List<Blog> list = dao.findPageBlogs(1, 4);
for(Blog blog : list) {
System.out.println(blog);
}

session.close();
}

/**
* 插入数据
*/
@Test
public void TestInsertBlog() {
SqlSession session = factory.openSession();
BlogDao dao = session.getMapper(BlogDao.class);
Blog blog = new Blog();
blog.setTitle("abc");
blog.setContent("abcd");
blog.setCreatedTime(new Date());
int n = dao.insertBlog(blog);
System.out.println("插入"+n+"条数据成功");
session.commit();
session.close();
}

/**
* 更新数据
*/
@Test
public void TestUpdateBlog() {
SqlSession session = factory.openSession();
BlogDao dao = session.getMapper(BlogDao.class);
Blog blog = new Blog();
blog.setId(6);
blog.setTitle("abcd");
blog.setContent("abcd");
int n = dao.updateBlog(blog);
System.out.println("更新"+n+"条数据成功");
session.commit();
session.close();

}

/**
* 删除数据
*/
@Test
public void TestDeleteBlog() {
SqlSession session = factory.openSession();
BlogDao dao = session.getMapper(BlogDao.class);
int n = dao.deleteBlog(6);
System.out.println("删除"+n+"条数据成功");
session.commit();
session.close();
}
}

day03:动态排序、日志配置、缓存配置

8.MyBatis业务增强

22.动态排序策略 

  1. 如何按照用户指定业务对数据进行排序?

例如:

1.博客系统

       a.按照创建时间对博客信息进行排序查询

       b.按照博客访问量对信息进行排序查询

2.电商系统

       a.按照商品价格对商品信息排序

       b.按照商品销量对商品信息排序

       c.按照商品好评对商品信息排序

解决方案:

  1. 写多个sql映射

  2. 写一个sql 映射,然后动态传参,借助${}表达式获取参数

例如

接口中方法定义

List<Blog> findBlogs(
@Param("column") String column,
@Param("seq") String seq);

映射文件中的实现

<select id="findBlogs"
resultType="blog">
select *
from blog
order by ${column} ${seq}
</select>

思考:

MyBatis中$与#有什么不同?

${}表达式主要用于获取配置文件数据,DAO接口中的参数信息,当$出现在映射文件的SQL语句中时创建的不是预编译的SQL,而是字符串的拼接,有可能会导致SQL注入问题.所以一般使用$接收dao参数时,这些参数一般是字段名,表名等,例如order by {column}.

#{}表达式主要用户获取DAO中的参数数据,在映射文件的SQL语句中出现#{}表达式,底层会创建预编译的SQL.性能会相对较好.

${}获取DAO参数数据时,参数必须使用@param注解进行修饰.

#{}获取DAO参数数据时,假如参数个数多于一个可有选择的使用@param.


 23.ID应用策略

1.保存数据时获取数据在数据库对应的主键值?

例如

  1. 订单系统?

保存订单信息时候,获取订单在数据库中的主键id值?

     2.权限系统

保存用户信息时,获取用户信息在数据库中的主键值?

   解决方案: 当对象对应的表中的记录为自增长时,可以采用如下方案

<insert id="insertObject"
parameterType="blog"
useGeneratedKeys="true"
keyProperty="id">
insert into blog
(id,title,content,createdTime)
values
(null,#{title},#{content},now())
</insert>

其中:keyProperty属性用于指定参数中的id属性.

2.当多线程并发的向表中写入数据时,假如id使用自增长可能存在线程安全问题?

例如:

  1. 秒杀系统

  2. 订票系统

  3. ....

解决方案:可将自增长的id设置为随机数,当然有些数据库根本就不支持自增长,此时也可以选择随机数.

数据准备:创建Author表

create table Author(
id varchar(200) primary key,
username varchar(100) unique not null,
password varchar(300) not null,
email varchar(50) unique
)engine=InnoDB;

借助mybatis 应用向表中写入数据,主键值要求通过UUID生成.其映射文件参考

<insert id="insertObject"
parameterType="author">
<selectKey keyProperty="id"
resultType="string"
order="BEFORE">
select replace(uuid(),'-','')
</selectKey>
insert into author
(id,username,password,email)
values
(#{id},#{username},#{password},#{email})
</insert>
@Test
public void insertAuthor2() {
SqlSession session =factory.openSession();
AuthorDao dao = session.getMapper(AuthorDao.class);
Author author = new Author();

author.setUserName("zhangsan5");
author.setPassWord("zhangsan5");
author.setEmail("zhangsan5@tedu.cn");
dao.insertAuthor2(author);
System.out.println("插入"+1+"条数据");
session.commit();
session.close();
}

4.MyBatis 高级应用

9.日志配置应用

24.日志基本概述

Mybatis内置的日志工厂提供日志功能,具体的日志实现有以下几种工具:

1)SLF4J(日志框架标准,类似JDBC标准)

2)Apache Commons Logging

3)Log4j 2 (是log4j的升级版,配置文件升级为xml格式了)

4)Log4j(日志处理库,配置文件格式为.properties)

5)JDK logging

项目中mybatis通常会借助第三方日志库进行日志的处理,例如log4j.

打印日志第一种方式:

package com.jt.util;
public class DebugConfig {
public static boolean DEBUG=true;
}
if(DebugConfig.DEBUG){
log.info("insert.rows="+rows);
System.out.println("insert.author="+entity);
}

打印日志第第二组种方式:

//JDK自带的日志对象
private Logger log= Logger.getLogger(getClass().getName());
log.info("insert.rows="+rows);

25.日志基本实现

配置步骤:(以log4j为例)

  1. 添加log4j依赖(一代)

<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

2.添加log4j.properties 配置(可以从其它项目中拷贝)

log4j.rootLogger=INFO,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d [%-5p] %c - %m%n
log4j.logger.com.mybatis3=DEBUG
log4j.logger.com.jt=DEBUG

2.添加log4j.properties 配置(可以从其它项目中拷贝)

log4j.rootLogger=INFO,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d [%-5p] %c - %m%n
log4j.logger.com.mybatis3=DEBUG
log4j.logger.com.jt=DEBUG

3.设置mybatis的日志实现(mybatis-configs.xml)

<!-- mybatis 核心配置文件(配置mybatis基础信息:例如连接,映射文件,...) -->
<configuration>
<properties resource="config.properties"></properties>
<!-- 启用log4j日志库 -->
<settings>
<setting name="logImpl" value="log4j" />
</settings>
<!-- 别名配置 -->
<typeAliases>
<!-- 为指定包中的所有类创建别名,别名默认为类名,但首字母小写。 -->
<package name="com.jt.entity" />
</typeAliases>

<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<!-- 映射路径 -->
<mappers>
<mapper resource="mapper/AuthorMapper.xml" />
</mappers>
</configuration>

其中name属性的值为固定写法,value的值要依托于使用的日志处理库.

说明:课后了解常用的日志处理库.


10.缓存配置应用

26.缓存基本概述

  1. 缓存是什么? 内存中的一个对象(容器).

  2. 缓存对象的作用?提高程序的性能(最主要的的是访问效率)

  3. MyBatis 中缓存概述?

MyBatis 框架中提供了非常强大的缓存特性来提高查询性能,通常可分为一级缓存(SqlSession级别)和二级缓(SqlSessionFactory).

    4.MyBatis 中的缓存应用.

在mybatis-configs.xml 中的<settings>标签里配置一级缓存

<settings>
<!-- 配置一级缓存 -->
<setting name="localCacheScope"  value="SESSION"/>
<!-- 配置二级缓存 -->
<setting name="cacheEnabled" value="true"/>
</settings>

27.缓存基本实现

MyBatis中一级缓存默认是开启的.不需要任何配置.

MyBatis:一级缓存应用说明:

1.默认是开启的(也是应用最多的一种)

2.其类型为SESSION或STATEMENT两种,默认是SESSION类型

        a.缓存对象的生命周期不同(例如session类型的一级缓存,session关闭就失效.)

        b.其类型的配置可在配置文件中通过这个localCacheScope属性进行配置。

3.一级缓存在每次更新后都会失效。

4.一级缓存在事务并发执行时可能会出现脏读,而STATEMENT不会出现脏读但效率会低一些。

例如:

@Test
public void testFindObjects(){
SqlSession session=factory.openSession();
AuthorDao dao=
session.getMapper(AuthorDao.class);
//==============
List<Author> list=
dao.findObjects();
session.close();
session=factory.openSession();
dao=session.getMapper(AuthorDao.class);
list=dao.findObjects();
//==============
session.close();
}
/**
* 测试一级缓存
* session类型的一级缓存,session关闭就失效.
* 结果:
*    对数据库进行两次查询,第一查询讲查出的数据放入一级缓存,
*    当session关闭后,一级缓存失效,所以第二次查询的时候
*    又对数据库进行一次查询,将结果放入一级缓存。
*/
@Test
public void testFindBlogById(){
//1.创建SqlSession
SqlSession session=factory.openSession();
//2.执行sql
AuthorDao dao=session.getMapper(AuthorDao.class);
String id="5e5f90ed324e11e8a9b279bf5362f090";
Author a1=dao.findAuthorById(id);
//Author a2=dao.findAuthorById(id); 数据从一级缓存取
session.close();//这个session的一级缓存销毁

//再次创建Session
session=factory.openSession();
dao=session.getMapper(AuthorDao.class);
Author a2=dao.findAuthorById(id);
session.commit();
//3.释放资源
session.close();
}
//======================打印日志===========================
2018-06-28 10:46:08,585 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - ==>  Preparing: select * from author where id=?
2018-06-28 10:46:08,607 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - ==> Parameters: 1(String)
2018-06-28 10:46:08,619 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - <==      Total: 1
Author [id=1, userName=张三, passWord=zhangsan, email=zhangsan@tedu.cn]
2018-06-28 10:46:08,623 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - ==>  Preparing: select * from author where id=?
2018-06-28 10:46:08,623 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - ==> Parameters: 1(String)
2018-06-28 10:46:08,624 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - <==      Total: 1
Author [id=1, userName=张三, passWord=zhangsan, email=zhangsan@tedu.cn]
/**
* session对数据有更新以后,缓存会失效
*/
@Test
public void testStairCache2() {
//查询
SqlSession session = factory.openSession();
AuthorDao dao = session.getMapper(AuthorDao.class);
String id ="1";
Author author1 =dao.findSelectAuthorById(id);
System.out.println(author1);
//设置author的值
author1.setUserName("张三");
author1.setPassWord("zhangsan");
author1.setEmail("zhangsan@tedu.cn");
//更改
dao.updateAuthor(author1);

//再次查询
Author author2 = dao.findSelectAuthorById(id);
System.out.println(author2);
session.commit();
session.close();
}
//======================打印日志===========================
2018-06-28 11:16:21,594 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - ==>  Preparing: select * from author where id=?
2018-06-28 11:16:21,615 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - ==> Parameters: 1(String)
2018-06-28 11:16:21,627 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - <==      Total: 1
Author [id=1, userName=李四, passWord=lisi, email=lisi@tedu.cn]
2018-06-28 11:16:21,628 [DEBUG] com.jt.dao.AuthorDao.updateAuthor - ==>  Preparing: update author set username=?, password=?, email=? where id=?
2018-06-28 11:16:21,629 [DEBUG] com.jt.dao.AuthorDao.updateAuthor - ==> Parameters: 张三(String), zhangsan(String), zhangsan@tedu.cn(String), 1(String)
2018-06-28 11:16:21,629 [DEBUG] com.jt.dao.AuthorDao.updateAuthor - <==    Updates: 1
2018-06-28 11:16:21,629 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - ==>  Preparing: select * from author where id=?
2018-06-28 11:16:21,629 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - ==> Parameters: 1(String)
2018-06-28 11:16:21,630 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - <==      Total: 1
Author [id=1, userName=张三, passWord=zhangsan, email=zhangsan@tedu.cn]
/**
* 多事务并发执行时,可能会出现脏读问题
* 脏读:一个事务读取到了另外一个事务没有提交的数据。
*/
@Test
public void testStairCache3() {
//查询;openSession(true):主动提交事务
SqlSession session1 = factory.openSession(true);
AuthorDao dao1 = session1.getMapper(AuthorDao.class);
SqlSession session2 = factory.openSession(false);
AuthorDao dao2 = session2.getMapper(AuthorDao.class);
String id ="1";
Author author1 =dao1.findSelectAuthorById(id);
System.out.println(author1);
//设置author的值
author1.setUserName("张三");
author1.setPassWord("zhangsan");
author1.setEmail("zhangsan@tedu.cn");
//更改
dao2.updateAuthor(author1);          
//再次查询
Author author2 = dao1.findSelectAuthorById(id);
System.out.println(author2);
session1.close();
session2.commit();
session2.close();
}
//======================打印日志===========================
2018-06-28 11:38:59,560 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - ==>  Preparing: select * from author where id=?
2018-06-28 11:38:59,582 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - ==> Parameters: 1(String)
2018-06-28 11:38:59,593 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - <==      Total: 1
Author [id=1, userName=李四, passWord=lisi, email=lisi@tedu.cn]
2018-06-28 11:38:59,596 [DEBUG] com.jt.dao.AuthorDao.updateAuthor - ==>  Preparing: update author set username=?, password=?, email=? where id=?
2018-06-28 11:38:59,597 [DEBUG] com.jt.dao.AuthorDao.updateAuthor - ==> Parameters: 张三(String), zhangsan(String), zhangsan@tedu.cn(String), 1(String)
2018-06-28 11:38:59,597 [DEBUG] com.jt.dao.AuthorDao.updateAuthor - <==    Updates: 1
Author [id=1, userName=张三, passWord=zhangsan, email=zhangsan@tedu.cn]

MyBatis 二级缓存默认是没有开启的,需要在映射文件中加上<Cache/>元素

MyBatis 二级缓存应用步骤:

Step01: 修改mybatis核心配置文件,添加缓存设置.

<!-- mybatis 核心配置文件(配置mybatis基础信息:例如连接,映射文件,...) -->
<configuration>
<properties resource="config.properties"></properties>
<!-- 启用log4j日志库 -->
<settings>
<setting name="logImpl" value="log4j" />
<!-- 配置一级缓存:本地缓存作用域 -->
<setting name="localCacheScope" value="SESSION"/>
<!-- 配置二级缓存:缓存启用 -->
<setting name="cacheEnabled" value="true"/>
</settings>
<!-- 别名配置 -->
<typeAliases>
<!-- 为指定包中的所有类创建别名,别名默认为类名,但首字母小写。 -->
<package name="com.jt.entity" />
</typeAliases>

<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<!-- 映射路径 -->
<mappers>
<mapper resource="mapper/AuthorMapper.xml" />
</mappers>
</configuration>

Step02: 在映射文件中配置Cache策略.

<!--
配置Cache策略
LRU           :最近最少使用算法
cache         :隐藏;
eviction      :回收
flushInterval :刷新间隔
size          :大小
readOnly      :只读
-->
<cache
eviction="LRU"
flushInterval="60000"
size="512"
readOnly="true">
</cache>

这个表示创建了一个 LRU缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会 导致冲突。其中:

1)  eviction 表示回收策略(例如LRU,FIFO等,默认为LRU)

2)  flushInterval 表示刷新间隔

3)  size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的 可用内存资源数目。默认值是 1024。

4)  readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。可读写的缓存会返回缓存对象的拷贝(通过序列化) 。这会慢一些,但是安全,因此默认是 false。

Step03: 使用二级缓存了.

readOnly(只读)属性可以被设置为 true时:

/**
* 测试二级缓存
* 二级缓存cache元素readOnly值为true,缓存中保存的是堆内
* 存中对象的引用.每次从缓存取数据都是获得的同一个对象.
*/
@Test
public void TestFoxbaseCache() {
SqlSession session = factory.openSession();
AuthorDao dao = session.getMapper(AuthorDao.class);
String id ="1";
Author author1 = dao.findSelectAuthorById(id);
System.out.println("author1"+author1);
session.close();

//此处更改的是缓存中的数据
session = factory.openSession();
dao = session.getMapper(AuthorDao.class);
Author author2 = dao.findSelectAuthorById(id);
author2.setUserName("李白");
System.out.println("author2"+author2);
session.close();

session = factory.openSession();
dao = session.getMapper(AuthorDao.class);
Author author3 = dao.findSelectAuthorById(id);
System.out.println("author3"+author3);
session.close();
}
//======================打印日志===========================
2018-06-28 14:35:29,299 [DEBUG] com.jt.dao.AuthorDao - Cache Hit Ratio [com.jt.dao.AuthorDao]: 0.0
2018-06-28 14:35:29,502 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - ==>  Preparing: select * from author where id=?
2018-06-28 14:35:29,525 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - ==> Parameters: 1(String)
2018-06-28 14:35:29,536 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - <==      Total: 1
author1Author [id=1, userName=张三, passWord=zhangsan, email=zhangsan@tedu.cn]
2018-06-28 14:35:29,540 [DEBUG] com.jt.dao.AuthorDao - Cache Hit Ratio [com.jt.dao.AuthorDao]: 0.5
author2Author [id=1, userName=李白, passWord=zhangsan, email=zhangsan@tedu.cn]
2018-06-28 14:35:29,540 [DEBUG] com.jt.dao.AuthorDao - Cache Hit Ratio [com.jt.dao.AuthorDao]: 0.6666666666666666
author3Author [id=1, userName=李白, passWord=zhangsan, email=zhangsan@tedu.cn]

readOnly(只读)属性可以被设置为 false时:

/**
* 测试二级缓存
* 二级缓存cache元素readOnly值为false,缓存中保存的是堆内
* 存中对象的引用.每次从缓存取数据都是获得的同一个对象.
*/
@Test
public void TestFoxbaseCache() {
SqlSession session = factory.openSession();
AuthorDao dao = session.getMapper(AuthorDao.class);
String id ="1";
Author author1 = dao.findSelectAuthorById(id);
System.out.println("author1"+author1);
session.close();

//此处更改的是缓存中的数据
session = factory.openSession();
dao = session.getMapper(AuthorDao.class);
Author author2 = dao.findSelectAuthorById(id);
author2.setUserName("王维");
System.out.println("author2"+author2);
session.close();

session = factory.openSession();
dao = session.getMapper(AuthorDao.class);
Author author3 = dao.findSelectAuthorById(id);
System.out.println("author3"+author3);
session.close();
}
//======================打印日志===========================
2018-06-28 14:43:11,081 [DEBUG] com.jt.dao.AuthorDao - Cache Hit Ratio [com.jt.dao.AuthorDao]: 0.0
2018-06-28 14:43:11,298 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - ==>  Preparing: select * from author where id=?
2018-06-28 14:43:11,324 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - ==> Parameters: 1(String)
2018-06-28 14:43:11,334 [DEBUG] com.jt.dao.AuthorDao.findSelectAuthorById - <==      Total: 1
author1Author [id=1, userName=张三, passWord=zhangsan, email=zhangsan@tedu.cn]
2018-06-28 14:43:11,817 [DEBUG] com.jt.dao.AuthorDao - Cache Hit Ratio [com.jt.dao.AuthorDao]: 0.5
author2Author [id=1, userName=王维, passWord=zhangsan, email=zhangsan@tedu.cn]
2018-06-28 14:43:11,818 [DEBUG] com.jt.dao.AuthorDao - Cache Hit Ratio [com.jt.dao.AuthorDao]: 0.6666666666666666
author3Author [id=1, userName=张三, passWord=zhangsan, email=zhangsan@tedu.cn]

FAQ?

1)MyBatis 二级缓存cache元素readOnly值的设置以及底层对象缓存过程.

readOnly说明:

readOnly的值为true时,缓存中保存的是堆内存中对象的引用.每次从缓存取数据都是获得的同一个对象.

readOnly为false时,首先会将查询到的对象,拷贝到缓存一份(对象需要实现序列化接口),然后从缓存取数据每次都是执行对象的拷贝. 


day04:高级映射、延迟加载、动态SQL

11.高级映射应用

28.高级映射基本概述

MyBatis中的高级映射一般要借助select元素中的resultMap属性进行实现,通过此属性配置实现一对一,一对多等关系映射的实现.

  1. 如何实现one2one映射?

  2. 如何实现one2many映射?

  3. 如何实现many2many映射?

思考:

  1. 查询博客信息时,将作者信息也查询出来?(many2one)

  2. 查询某个用户的同时,将其对应的博客列表信息也查询出来(one2many)

  3. .....


 29.高级映射基本实现

课堂案例:

  1. 在blog表中添加一个字段,名字为authorId,类型为string.

alter table blog add authorId varchar(200);

  1. 为blog表中的authorId字段赋值,其值为author表中某些记录的主键值.

update blog set authorId=? where id=?

  1. 查询某个blog信息,并将其关联的author对象信息查询出来.

方案一:

Step01: BlogDao接口中方法定义:

Map<String,Object>
findBlogAuthorById(Integer id);

Step02: BlogMapper中映射元素定义:

<select id="findBlogAuthorById"
resultType="map">
select b.*,a.username,a.email
from blog b join author a
on b.authorId=a.id
where b.id=#{id}       
</select>

方案二:

Step01:com.jt.vo.BlogResult 值对象定义(借助此对象封装多表数据)

public class BlogResult {
private Integer id;
private String title;
private String content;
private Date createdTime;
private Author author;
...set/get
}

Step02:BlogDao接口中方法定义:

BlogResult findBlogResultById(Integer id);

Step03:BlogMapper中映射元素定义

property:属性  

column:柱

<select id="findBlogResultById"
resultMap="blogResult">
select b.*,a.id authorId,a.username,a.email
from blog b join author a
on b.authorId=a.id
where b.id=#{id}       
</select>
<resultMap id="blogResult" type="com.jt.vo.BlogResult">
<id property="id" column="id"/>
<result property="title" column="title"/>
<result property="content" column="content"/>
<result property="createdTime" column="createdTime"/>
<!-- 关联映射 -->
<association property="author" javaType="author">
<id property="id" column="authorId"/>
<result property="username" column="username"/>
<result property="email" column="email"/>
</association>
</resultMap>

优势:

空间利用率有可能会有所提升,对象可读性有一定成都的提升。

缺陷:

映射文件中的代码量相对较大,映射相对复杂,可读性不太好。

Step04: 单元测试

方案三:(通过两次查询实现)

Step01: 接口中方法定义

BlogResult findBlogResultWithId(Integer id);

Step02: 映射文件元素定义

<resultMap type="com.jt.vo.BlogResult"
id="blogResultMap">
<association property="author"
column="authorId"
javaType="author"
select="com.jt.dao.AuthorDao.findObjectById">
</association>
</resultMap>
<select id="findBlogResultWithId"
resultMap="blogResultMap">
select * from blog where id=#{id}       
</select>


12.延迟加载应用

30.延迟加载基本概述

延迟加载是按需加载的一种实现策略,一般应用与关联查询中,针对关联对象数据进行延迟加载(何时需要何时加载).以提高内存的使用效率。


31.延迟加载基本实现

Step01: 添加依赖(CGLIB依赖,底层构建代理对象时需要)

<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version>
</dependency>

Step02: 配置全局延迟加载(当有些查询不需要延迟加载,可以在查询对应属性中使用fetchType进行覆盖性设置,例如值为lazy表示延迟加载,eager表示实时加载)

<settings>
....
<!-- 配置全局延迟加载;lazyLoadingEnabled:延迟加载启用-->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 设置按需加载(配合上面的延迟加载属性实现;aggressiveLazyLoading积极的延迟加载) -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>

Step03: 关联映射中就可以直接使用延迟加载了.例如

<resultMap type="com.jt.vo.BlogResult"
id="blogResultMap">
<association property="author"
column="authorId"
javaType="author"
select="com.jt.dao.AuthorDao.findObjectById">
</association>
</resultMap>
<select id="findBlogResultWithId"
resultMap="blogResultMap">
select * from blog where id=#{id}       
</select>

当在测试类中只访问blog信息时,不会查询author信息,创建author对象.除非再

在association元素中设置fetchType属性.


13.动态SQL应用

32.动态SQL基本概述

思考:

如何动态删除客户端选择的记录,用户有可能会选择一个记录,也可能会选择多个记录然后进行删除.那么在mybatis的映射文件中该如何配置,如何实现或者说解决这种动态需求问题?

解决方案:借助动态sql实现。

动态sql


33.动态SQL基本实现

动态sql.(以更加灵活的方法解决业务中的数据操作问题)

MyBatis 中常用动态sql元素:foreach,if,where,trim,.....

本小结以foreache为案例,实现一个动态删除操作,其步骤如下:

step01:BlogDao接口中方法定义

int deleteObjectByIds(
@Param("ids") String[] ids);

step02:BlogMapper文件中定义删除元素

<delete id="deleteObjectByIds"
parameterType="string">
delete from blog
where id in  <!-- (10,11)-->
<!-- 动态sql forearch
collection 的值为dao传递的参数
item为for循环形参变量
separator 用于指定分隔符
-->
<foreach collection="ids"
open="("
close=")"
separator=","
item="item">
#{item}
</foreach>
</delete>

说明:当在foreach 属性直接使用ids接收dao中参数数据时,dao接口方法应

使用@Param注解进行声明.假如没有使用注解声明可以使用 array接收到方法中参数数组数据

step03:编写单元测试

@Test
public void testDeleteObjectByIds(){
//1.创建session
SqlSession session=factory.openSession();
//2.执行sql
//2.1获取dao对象
BlogDao dao=session.getMapper(BlogDao.class);
int rows=
dao.deleteObjectByIds(new String[]{"9"});
System.out.println("delete.rows="+rows);
session.commit();
//3.关闭session
session.close();
}

5.总结

14.重点和难点分析

Day01:

  1. MyBatis 是什么,要解决什么问题?

  2. MyBatis 底层架构体系?

  3. MyBatis 核心组件以及API?

  4. MyBatis 编程的基本步骤?

  5. MyBatis 数据操作执行流程?

  6. ...

Day02:

1.MyBatis 框架编程中CRUD操作的基本实现?

  1. Session.selectOne(….),session.selectList(…)

  2. Session.insert(“命名空间+元素id”),….

  3. Session.update(…),….

  4. Session.delete(….),…..

2.MyBatis 框架编程中的事务处理(自动提交事务,手动提交事务)?

  1. factory.openSession(true),自动提交

  2. factory.openSession();默认false,为手动提交

3.MyBatis 框架编程中基于DAO接口的CRUD实现方式?

  1. 定义DAO接口

  2. 定义Mapper映射文件

  3. Mapper文件与DAO接口之间的映射(命名空间,元素id,参数)

4.MyBatis 框架编程中DAO接口与Mapper映射的绑定规则?

  1. DAO的类全名与mapper的命名空间相同

  2. DAO类的方法名与mapper文件的元素id相同

  3. DAO类中的方法参数与mapper文件中参数获取对应

5.MyBatis 框架编程中数据库连接信息的配置及获取方式?

  1. UNPOOLED(不使用连接池):了解,每次访问数据库都会创建一个新的连接。

  2. POOLED (内置连接池):重点掌握。可以实现Connection对象的复用

  3. JNDI(使用命名空间目录接口服务):了解

6.MyBatis 框架编程中映射文件内部的对象别名配置?

  1. 配置文件中通过typeAliases元素进行配置

  2. 应用于映射文件中参数类型(parameterType),结果类型(resultType)


15.常见FAQ

  1. MyBatis 底层数据方法需要JDBC吗?

  2. MyBatis 核心配置文件中有哪些常用配置?

  3. MyBatis 映射文件中常用元素定义有哪些?

  4. MyBatis 数据操作常用实现方式有哪些?

  5. MyBatis 映射文件元素如何获取参数数据?

  6. MyBatis 映射文件元素中获取参数数据的常用方案.

  7. ...


16.作业

  1. 总结课堂知识点

  2. 完成课堂案例

  3. 编写基于接口方式的更新以及删除操作

Day01:

  1. 了解本阶段课程目标,内容,特点。

  2. 掌握京陶权限管理子系统的导入及部署方式

  3. 掌握基于maven的mybatis项目创建方式及问题解决方案。

  4. 掌握mybatis核心架构体系以及基本API的简单应用

  5. 总结课堂内容并实践基于mybatis的数据查询操作。

Day02:

1.理解mybatis框架底层映射原理?(例如记录到map对象的映射)

  1. 写入数据(将内存中的对象映射为数据库中的记录)

  2. 获取数据(将数据库中的数据映射内存中对象):

  3. 技术实现(反射+元数据:表中字段,类中属性)

2.总结并实践基于MyBatis框架实现的基本CRUD操作。

  1. Maven项目+依赖+配置文件+映射文件+API

3.总结并实践MyBatis框架中基于接口方式CRUD操作实现。

  1. 基于接口方式的优势?(面向接口编程,提高程序可读性,可维护性。)

  2. 基于接口方式的劣势?(还需要写接口,代码量会有一定的提高)

4.总结MyBatis框架编程中DAO参数定义与Mapper文件中参数获取的方式。

1)下标方式:例如#{0},#{1},…

2)参数方式:  #{param1},#{param2}

3)key方式:  #{pageSize},#{startIndex}

5.尝试实践mybatis编程进阶中的业务增强实现。



作者:Darren

QQ:603026148

以上内容归Darren所有,如果有什么错误或者不足的地方请联系我,希望我们共同进步。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

从码农到码到成功

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值