MyBatis框架
1.框架概述
1.1软件开发的常用架构
1.1.1三层架构
三层架构包含的三层:
- 界面层
- 业务逻辑层
- 数据访问层
三层架构的职责:
- 界面层(表示层,视图层):主要功能是接受客户端的请求并响应数据给客户端。
- 业务逻辑层:接收表示传递过来的数据,检查数据,调用数据访问层获取数据。
- 数据访问层:与数据库交互,主要实现对数据的CRUD操作。将存储在数据库中的数据提交给业务层,同时将经过业务层处理的数据保存到数据库。
使用三层架构的优点:
- 降低耦合度,各层分工明确。
- 容易后期的维护和扩展。
- 有利于标准化。
1.1.2 常用框架
MyBatis框架:MyBatis是一个优秀的基于java持久层框架,内部封装了JDBC,开发者只需要关注sql语句本身,而不需要处理加载驱动,创建连接,statement,关闭连接,资源等繁杂的过程。
MyBatis通过xml或注解两种方式将要执行的各种sql语句配置起来,并通过java对象,和sql动态参数进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射为java对象,并返回。
Spring框架:Spring框架为了解决软件开发的复杂性而创建。Spring使用的是基本的javabean来完成以前复杂的企业级开发应用。Spring解决了业务对象,功能模块之间的耦合,不仅在javase,web中使用,大部分Java应用都可以从Spring中受益。
Spring是一个轻量级控制反转(IOC)和面向切面(AOP的容器)。
SpringMVC框架:SpringMVC属于SpringFrameWork3.0版本加入的一个模块,为Spring框架提供了构建web应用程序的能力。现在可以使用Spring框架提供的SpringMVC模块实现web应用开发,在web项目中可以无缝使用Spring和SpringMVC框架。
1.2 框架是什么
1.2.1 框架定义
框架是为开发者定制的应用骨架,模板。
1.2.2 框架解决的问题
框架要解决的最重要的问题是技术的整合。
1.3 使用JDBC的缺陷
- 代码繁杂,开发效率低
- 需要关注Connection,Statement,Result对象的创建和销毁
- 对ResultSet查询的结果,需要自己封装为List
- 重复的代码较多
- 业务代码和数据库的操作混在一起,耦合度较高
1.4MyBatis解决的主要问题
减轻使用JDBC的复杂性,不用编写重复的创建Connection,Statement;不用编写关闭资源的代码。直接使用Java对象,表示结果数据。让开发者专注于Sql的处理。其它分心的工作由MyBatis代劳。
MyBatis可以完成:
- 注册数据库的驱动,例如Class.forName(“com.mysql.jdbc.Driver”)
- 创建JDBC中必须使用的Connection,Statement,RusultSet对象
- 从 xml 中获取 sql,并执行 sql 语句,把 ResultSet 结果转换 java 对象 List list = new ArrayLsit<>(); ResultSet rs = state.executeQuery(“select * from student”); while(rs.next){ Student student = new Student(); student.setName(rs.getString(“name”)); student.setAge(rs.getInt(“age”)); list.add(student); }
- 关闭资源:ResultSet.close() , Statement.close() , Conenection.close()
2.MyBatis框架快速入门
内容:
- 快速开始一个MyBatis
- 基本的CRUD的操作
- MyBatis内部对象分析
- 使用Dao对象
2.1 入门案例
2.1.1使用mybatis准备
下载mybatis
2.1.2 搭建Mybatis开发环境
- 创建mysql数据库和表
- 创建maven工程
- 加入maven坐标
pom.xml加入maven坐标:
1 | <dependencies> |
- 加入maven插件
1 | <build> |
- 编写student类
1 | package com.atguigu.pojo; |
- 编写Dao接口StudentDao
1 | package com.atguigu.dao; |
- 编写Dao接口Mapper映射文件StudentDao.xml
要求:
- 在dao包中创建文件StudentDao.xml
- 要StudentDao.xml文件名称和接口StudentDao一样(区分大小写写的一样)
1 |
|
- 创建MyBatis主配置文件
1 |
|
- 创建测试类MyBatisTest
1 | package com.atguigu; |
- 配置日志功能
mybatis.xml文件中加入日志配置,可以在控制台输出执行的sql语句和参数
1 | <settings> |
2.2基本的CRUD
2.2.1 insert
(1) StudentDao接口中增加的方法
1 | int addStudent(Student student); |
(2) StudentDao.xml 加入 sql 语句
1 | <insert id="addStudent"> |
(3) 增加测试方法
1 |
|
2.2.2 update
(1) StudentDao 接口中增加方法
1 | int updateStudent(Student student); |
(2)StudentDao.xml 增加 sql 语句
1 | <update id="updateStudent"> |
(3)增加测试方法
1 |
|
2.2.3 delete
(1) StudentDao 接口中增加方法
1 | int deleteStudent(Integer id); |
(2)StudentDao.xml 增加 sql 语句
1 | <delete id="deleteStudent"> |
(3)增加测试方法
1 |
|
2.3 MyBatis对象分析
2.3.1 对象使用
SqlSession , SqlSessionFactory 等
(1) Resource类
Resource类,顾名思义就是资源,用于读取资源文件。其有很多方法通过加载并解析资源文件,返回不同类型的IO流对象。
(2)SqlSessionFactoryBuilder类
SqlSessionFactory的创建需要使用SqlSessionFactoryBuilder对象的build()方法。由于SqlSessionFactoryBuilder对象在创建完工厂以后,就完成了其历史使命,即可被销毁,所以,一般会将该SqlSessionFactoryBuilder对象创建为一个方法内的局部对象,方法结束,对象销毁。
(3)SqlSessionFactory接口
SqlSessionFactory接口对象是一个重量级对象(系统开销大的对象,是线程安全的,所以一个应用只需要一个该对象即可。创建SqlSession对象需要使用SqlSessionFactory接口的openSession()方法)
- openSession(true):创建一个有自动提交功能的SqlSession
- openSession(false):创建一个非自动提交功能的SqlSession,需要手动提交
- openSession():同openSession(false)
(4) SqlSession接口
SqlSession接口对象用于执行持久化操作。一个SqlSession对应着一次数据库会话,一次会话以SqlSession对象的创建开始,以SqlSession对象的关闭结束。
SqlSession接口对象是线程不安全的,所以每次数据库会话结束前,需要马上调用其close()方法,将其关闭。再次需要会话,再次创建,使用完毕后关闭。
2.3.2 创建工具类
(1) 创建MyBatisUtil工具类
1 | package com.atguigu.util; |
2.4MyBatis使用传统Dao开发方式
Dao 的实现类其实并没有干什么实质性的工 作,它仅仅就是通过 SqlSession 的相关 API 定位到映射文件 mapper 中相应 id 的 SQL 语句,真正对 DB 进 行操作的工作其实是由框架通过 mapper 中的 SQL 完成的。
所以,MyBatis 框架就抛开了 Dao 的实现类,直接定位到映射文件 mapper 中的相应 SQL 语句,对 DB 进行操作。这种对 Dao 的实现方式称为 Mapper 的动态代理方式。
Mapper 动态代理方式无需程序员实现 Dao 接口。接口是由 MyBatis 结合映射文件自动生成的动态代理实现的。
3.MyBatis框架Dao代理
3.1 Dao代理实现CRUD
3.1.1步骤
(1) 去掉Dao接口实现类
(2)通过SqlSession的getMapper方法获取代理对象
只需要调用SqlSession的getMapper()方法,即可获取指定的接口实现类的对象。该方法的参数为指定Dao接口类的class值。
1 | SqlSession sqlSession = MyBatisUtils.getSqlSession(); |
(3)使用Dao代理对象方法执行dSql语句
1 |
|
3.1.2 原理
动态代理
3.2深入理解参数
3.2.1 parameterType
parameterType: 接口中方法参数的类型,类型的完全限定名称或别名。这个属性是可选的,因为MyBatis可以推断出具体传入语句的参数,默认值为未设置(unset)。接口中方法的参数从java代码传入到mapper文件的sql语句中。
1 | 例如: |
3.2.2 MyBatis传递参数
从java代码中把参数传递到mapper.xml文件中。
3.2.3 一个简单参数的传递
Dao接口中方法参数只有一个简单的类型(java基本类型和String),z占位符 #{任意字符};和方法的参数名无关。
接口方法
1 | Student selectById(int id); |
mapper文件:
1 | <select id="selectById" resultType="com.atguigu.pojo.Student"> |
测试方法:
1 |
|
3.2.4多个参数-使用@Param
当Dao接口方法中有多个参数时,需要通过名称使用参数。在方法形参前面加上@Param(“自定义参数名”),在mapper文件中使用#{自定义参数名}。
接口方法
1 | List<Student> selectMultiParam( String name, |
mapper文件:
1 | <select id="selectMultiParam" resultType="com.atguigu.pojo.Student"> |
测试方法:
1 |
|
3.2.5多个参数-使用对象
使用java对象传递参数,java的属性值就是sql需要的参数值。每一个属性就是一个参数。
语法格式:#{property,javaType=java中的数据类型名,jdbcType=数据类型名称}
javaType, jdbcType 的类型 MyBatis 可以检测出来,一般不需要设置。常用格式 #{ property }
接口方法:
1 | public int insertStudent(Student student); |
mapper文件:
1 | <insert id="insertStudent"> |
3.2.6多个参数-按位置
参数位置从0开始,引用参数语法 #{arg位置},第一个参数是#{arg0},第二个是#{arg1}。
接口方法:
1 | List<Student> selectByNameAndAge(String name,int age); |
mapper文件:
1 | <select id="selectByNameAndAge" resultType="com.atguigu.pojo.Student"> |
3.2.7多个参数使用Map
Map集合可以储存多个值,使用Map向mapper文件中一次传入多个参数。Map集合使用String的key,Object类型的值存储参数。mapper文件使用**#{key}**引用值。
接口方法:
1 | List<Student> selectMultiMap(Map<String,Object> map); |
mapper文件:
1 | <select id="selectMultiMap" resultType="com.atguigu.pojo.Student"> |
测试方法:
1 |
|
3.2.8#和$的区别
#:占位符,告诉 mybatis 使用实际的参数值代替。并使用 PrepareStatement 对象执行 sql 语句, #{…}代替 sql 语句的“?”。这样做更安全,更迅速,通常也是首选做法,
$ 字符串替换,告诉 mybatis 使用$包含的“字符串”替换所在位置。使用 Statement 把 sql 语句和${}的 内容连接起来。主要用在替换表名,列名,不同列排序等操作。
3.3封装为MyBatis输出结果
3.3.1 resultType
resultType: 执行 sql 得到 ResultSet 转换的类型,使用类型的完全限定名或别名。 注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。resultType 和 resultMap,不能同时使用。
(1)简单类型
接口方法:
1 | int countStudent(); |
mapper文件:
1 | <select id="countStudent" resultType="int"> |
测试方法:
1 |
|
(2)对象类型
接口方法:
1 | Student selectById(int id); |
mapper文件:
(使用全限定名称)
1 | <select id="selectById" resultType="com.atguigu.pojo.Student"> |
(使用别名):需要在mybatis主配置文件中配置(mybatis.xml)
mybatis.xml:
1 | <!-- 定义别名--> |
mapper文件:
1 | <select id="selectById" resultType="Student"> |
框架的处理:使用构造方法创建对象。调用 setXXX 给属性赋值。
注意:Dao 接口方法返回是集合类型,需要指定集合中的类型,不是集合本身。
(3)Map
sql 的查询结果作为 Map 的 key 和 value。推荐使用 Map。 注意:Map 作为接口返回值,sql 语句的查询结果最多只能有一条记录。大于一条记录是错误。
接口方法:
1 | Map<Object,Object> selectReturnMap(int id); |
mapper文件:
1 | <select id="selectReturnMap" resultType="java.util.HashMap"> |
测试方法:
1 |
|
3.3.2resultMap
resultMap 可以自定义 sql 的结果和 java 对象属性的映射关系。更灵活的把列值赋值给指定属性。 常用在列名和 java 对象属性名不一样的情况。
使用方式:
- 先定义resultMap,指定列名和属性的对应关系。
- 在< select >中把resultType替换为resultMap.
接口方法:
1 | List<Student> selectAllStudents(); |
mapper文件:
1 | <!-- 使用resultMap |
测试方法:
1 |
|
3.3.3实体类属性名和列名不同的处理方式
(1)使用列别名和< resultType >
创建新的实体类MyStudent
1 | package com.atguigu.pojo; |
接口方法:
1 | List<MyStudent> selectDifColumnProperty(); |
mapper文件:
1 | <!-- 列名和属性名不一致 第一种方式 |
测试方法:
1 |
|
(2)使用resultMap
接口方法:
1 | List<MyStudent> selectMyStudent(); |
mapper文件:
1 | <!-- 列名和属性不一样 第二种方式--> |
测试方法:
1 |
|
3.4模糊查询
模糊查询的实现有两种方式, 一是 java 代码中给查询数据加上“%” ; 二是在 mapper 文件 sql 语句的条件位置加上“%”
第一种模糊查询 : 在java代码中指定like的内容
接口方法:
1 | /* |
mapper文件:
1 | <!-- 第一种like |
测试方法:
1 |
|
第二种模糊查询:
接口方法:
1 | /* |
mapper文件:
1 | <!-- 第二种方式 |
测试方法:
1 |
|
4.MyBatis框架动态sql
内容列表:
- 动态 SQL-if
- 动态 SQL-where
- 动态 SQL-foreach
- 动态 SQL-片段
动态 SQL,通过 MyBatis 提供的各种标签对条件作出判断以实现动态拼接 SQL 语句。这里的条件判 断使用的表达式为 OGNL 表达式。常用的动态 SQL 标签有、、、等。 MyBatis 的动态 SQL 语句,与 JSTL 中的语句非常相似。
动态 SQL,主要用于解决查询条件不确定的情况:在程序运行期间,根据用户提交的查询条件进行 查询。提交的查询条件不同,执行的 SQL 语句不同。若将每种可能的情况均逐一列出,对所有条件进行 排列组合,将会出现大量的 SQL 语句。此时,可使用动态 SQL 来解决这样的问题
4.1 动态sql之< if >
对于该标签的执行,当 test 的值为 true 时,会将其包含的 SQL 片断拼接到其所在的 SQL 语句中。 语法: sql 语句的部分
接口方法:
1 | List<Student> selectStudentIf(Student student); |
mapper文件:
1 | <select id="selectStudentIf" resultType="com.atguigu.pojo.Student"> |
测试方法:
1 |
|
4.2 动态sql之< where >
< if > 标签的中存在一个比较麻烦的地方:需要在 where 后手工添加 1=1 的子句。因为,若 where 后 的所有条件均为 false,而 where 后若又没有 1=1 子句,则 SQL 中就会只剩下一个空的 where,SQL 出错。所以,在 where 后,需要添加永为真子句 1=1,以防止这种情况的发生。但当数据量很大时,会 严重影响查询效率。
使用< where >标签,在有查询条件时,可以自动添加上 where 子句;没有查询条件时,不会添加 where 子句。需要注意的是,第一个标签中的 SQL 片断,可以不包含 and。不过,写上 and 也不错, 系统会将多出的 and 去掉。但其它中 SQL 片断的 and,必须要求写上。否则 SQL 语句将拼接出错
接口方法:
1 | List<Student> selectStudentWhere(Student student); |
mapper文件:
1 | <select id="selectStudentWhere" resultType="com.atguigu.pojo.Student"> |
测试方法:
1 |
|
4.4 动态sql之< foreach >
标签用于实现对于数组与集合的遍历。对其使用,需要注意: ➢ collection 表示要遍历的集合类型, list ,array 等。 ➢ open、close、separator 为对遍历内容的 SQL 拼接。
- collection 表示要遍历的集合类型, list ,array 等。
- open、close、separator 为对遍历内容的 SQL 拼接。
语法:
1 | <foreach collection="集合类型" open="开始的字符" close="结束的字符" |
4.4.1遍历 List<简单类型>
需求:查询学生 id 是 1002,1005,1006
接口方法:
1 | List<Student> selectStudentForList(List<Integer> idList); |
mapper文件:
1 | mapper 文件: |
测试方法:
1 | 测试方法: |
4.4.2 遍历List<对象类型>
接口方法:
1 | List<Student> selectStudentForList2(List<Student> stuList); |
mapper文件:
1 | <select id="selectStudentForList2" |
测试方法:
1 |
|
4.5 动态sql之代码片段
标签用于定义 SQL 片断,以便其它 SQL 标签复用。而其它标签使用该 SQL 片断,需要使用 子标签。该标签可以定义 SQL 语句中的任何部分,所以子标签可以放在动态 SQL 的任何位置。
mapper文件:
1 |
|
5.分页PageHelper的使用
实现步骤:
(1)添加maven坐标
1 | <dependency> |
(2) 加入加入 plugin 配置
在< environments >之前加入
1 |
|
(3) 在查询语句前使用:PageHelper对象
查询语句之前调用 PageHelper.startPage 静态方法。 除了 PageHelper.startPage 方法外,还提供了类似用法的 PageHelper.offsetPage 方法。 在你需要进行分页的 MyBatis 查询方法前调用 PageHelper.startPage 静态方法即可,紧跟在这个 方法后的第一个 MyBatis 查询方法会被进行分页。
1 |
|
6.mapper文件以及mybatis主配置文件代码
6.1 mybatis-demo1
mapper文件:
1 |
|
mybatis.xml:
1 |
|
6.2 mybatis-demo2
mapper文件:
1 |
|
mybatis.xml:
1 |
|
6.3 mybatis-demo3
1 |
|
mybatis.xml:
1 |
|
6.4 mybatis-dynamic-sql
mapper文件:
1 |
|
mybatis.xml:
1 |
|