黑马程序员技术交流社区
标题:
mybatis
[打印本页]
作者:
施主
时间:
2019-4-13 15:08
标题:
mybatis
Mybatis
maven回顾
1. 创建maven
2. 导入maven工程
3. 检查maven工程环境
1. 全部报红:maven环境配置不对
2. 部分报红:idea没有及时更新
1. 关闭工程然后打开
4. 1
mybatis入门
概述
1. 三层架构:
1. 持久层 :dao domino
2. 业务层:service
3. 表现层(UI层):Servlet
- jsp --> servlet --> html
2. 什么是框架?
- 框架是针对某一层的完整解决方案,不同的框架解决不同的问题。对某一层的复杂代码进行了封装。从而是开发中更多精力专注于业务功能的实现,大大提高了开发效率。
3. mybatis框架
- 明确:它是一个持久层框架,解决项目对数据库的CRUD操作。
4. 持久化技术解决方案
1. JDBC技术:
1. JDBC是规范
2. Spring的JdbcTemplate 和Apache的DbUtils都只是工具类
5. mybatis 概述
1. mybatis是一个用Java编写的持久层框架。
2. 使用ORM思想实现了结果集的封装。
6. ORM: 对象关系映射
- 通过建立数据库表和Java实体类的对应关系,从而实现操作实体类就相当于操作数据库表。
原理:
1. 解析xml,通过映射文件 获得一个map集合
1. map集合中每一个元素都是k,v的组合
2. k:名称空间(接口名)+操作的id(方法名)
3. v: (sql+返回值+参数类型)mapper对象
2. 获取动态代理对象:通过动态代理,在内存中根据接口生产的一个实现类(mybatis创建的实现类)
3. 动态代理对象调用方法时,mybatis将该方法封装成字符串,获取map集合中的mapper对象
原理:
环境搭建
1. 创建maven工程并导入坐标
2. 创建实体类和dao的接口
3. 创建Mybatis的主配置文件
- SQLMapConfig.xml
4. 创建映射配置文件
- IUserDao.xml
环境搭建的注意事项:
1. 创建IUserDao.xml 和 IUserDao.java 时名称是为了和我们之间的知识保持一致。在Mybatis中把持久层的操作接口名称和映射文件也叫做:Mapper。所以: IUserDao 和 IUserMapper是一样的。
2. 在idea中创建目录的时候,它和包是不一样的。包在创建时:直接可以通过 . 创建多级目录,而在resources中他为一级目录。
3. mybatis的映射配置文件位置必须和dao接口的包结构相同。
4. 映射配置文件的mapper标签namespace属性的取值必须是dao接口的全限定类名称
5. 映射配置文件的操作配置(select),id属性的取值必须是dao接口的方法名。
入门案例
1. 读取配置文件
2. 创建SQLSessionFactory工厂
3. 创建SQLSession
4. 创建Dao接口的代理对象
5. 执行dao中的方法
6. 释放资源
自定义框架
mybatis 基本使用
1. 单表的crud操作
JavaType属性,当数据库类型和封装类型一致时,可以省略不写。
2. dao编写
3. 配置的细节
1. parameterType属性:
- 代表参数的类型,自定义类写全路径,Java long包下的类直接写类名
2. sql语句中使用#{}字符:
- 代表占位符,相当于原来jdbc中的? ,都是用于执行语句是替代实际的数据。#{} 会对特殊字符进行转译,防止sql语句注入。
3. #{}中内容的写法:
- 由于我们保存方法的参数是 一个User对象,此处要写User对象中的属性名称。 它用的是ognl表达式。
4. ognl表达式:
- 它是apache提供的一种表达式语言,对象图导航语言 。它是按照一定的语法格式来获取数据的。
- 语法格式就是使用 #{对象.对象}的方式。
- *#{user.username}它会先去找user对象,然后在user对象中找到username属性,并调用getUsername()方法把值取出来。
- 但是我们在parameterType属性上指定了实体类名称,所以可以省略user.而直接写username。
5. 增删改数据时,需要手动提交事务
- 可以使用:session.commit();来实现事务提交。
6. 添加数据后返回值的问题:
- 新增用户后,同时还要返回当前新增用户的id值,因为id是由数据库的自动增长来实现的,所以就相当于我们要在新增后将自动增长auto_increment的值返回。
<selectKey keyColumn="id" keyProperty="id" resultType="int">
select last_insert_id();
</selectKey>
7. #{}与${}的区别
1. #{}表示一个占位符号
1. 通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
2. ${}表示拼接sql串
1. 通过{}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, {}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。
4. 标签的使用
1. resultMap标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系。从而实现封装。
在select标签中使用resultMap属性指定引用即可。同时resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询。
<!-- 建立User实体和数据库表的对应关系
type属性:指定实体类的全限定类名 id属性:
给定一个唯一标识,是给查询select标签引用用的。 -->
<resultMap type="com.itheima.domain.User" id="userMap">
<id column="id" property="userId"/>
<result column="username" property="userName"/>
<result column="sex" property="userSex"/>
<result column="address" property="userAddress"/>
<result column="birthday" property="userBirthday"/>
</resultMap>
id标签:用于指定主键字段
result标签:用于指定非主键字段
column属性:用于指定数据库列名
property属性:用于指定实体类属性名称
配置查询语句
<!-- 配置查询所有操作 -->
<select id="findAll" resultMap="userMap">
select * from user
</select>
Mybatis与JDBC编程的比较
1. 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
解决:
在SqlMapConfig.xml中配置数据链接池,使用连接池管理数据库链接。
2. Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
解决:
将Sql语句配置在XXXXmapper.xml文件中与java代码分离。
3. 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数对应。
解决:
Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。
4. 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
解决:
Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。
SqlMapConfig.xml中配置的内容和顺序
-properties(属性)
--property
-settings(全局配置参数)
--setting
-typeAliases(类型别名)
--typeAliase
--package
-typeHandlers(类型处理器)
-objectFactory(对象工厂)
-plugins(插件)
-environments(环境集合属性对象)
--environment(环境子属性对象)
---transactionManager(事务管理)
---dataSource(数据源)
-mappers(映射器)
--mapper
--package
1. properties标签配置
<!-- 配置连接数据库的信息
resource属性:用于指定properties配置文件的位置,要求配置文件必须在类路径下
resource="jdbcConfig.properties" -->
<properties resource= “jdbcConfig.properties"> </properties>
2. typeAliases(类型别名)
在SqlMapConfig.xml中配置:
<typeAliases>
<!-- 单个别名定义 -->
<typeAlias alias="user" type="com.itheima.domain.User"/>
<!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) -->
<package name="com.itheima.domain"/>
<package name="其它包"/>
</typeAliases>
mybatis 深入和多表
1. 连接池
maybatis连接池提供了3种方式的配置:
配置的位置:
主配置文件SqlMapConfig.xml中的dataSource标签,type属性就是表示采用何种连接池方式。
type属性的取值:
1. POOLED 采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现
1. 使用连接池的数据源
1. 空闲池:没有使用的连接对象
2. 活动池: 正在使用的连接对象
3. 用户使用连接池获取连接对象,先查询空闲池是否有对象,如果有调出使用,如果没有继续查询活动池是否装满,如果没装满就新建一个连接对象使用。如果活动池装满,就将最先创建的连接对象格式化后交给对象使用。
2. UNPOOLED (不使用连接池的数据源,每次都重新创建新的连接,用完立刻销毁)采用传统的获取连接的方式,虽然也实现Javax.sql.DataSource接口,但是并没有使用池的思想。
3. JNDI 采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到DataSource是不一样。
注意:如果不是web或者maven的war工程,是不能使用的。
我们课程中使用的是tomcat服务器,采用连接池就是dbcp连接池。
2. 事务控制及设计的方法
3. 动态sql
1. if 标签 :条件判断标签
1. 如果传递参数为单值,使用_parameter获取参数
2. 如果传递的数据为单个字符,xml默认其为字符,需要转换为字符串。 eg:“L” == 'L'.toString();
2. where 标签:条件拼接标签
3. foreeach 标签:迭代添加
<!-- 查询所有用户在id的集合之中 -->
<select id="findInIds" resultType="user" parameterType="queryvo">
<!-- select * from user where id in (1,2,3,4,5); -->
<include refid="defaultSql">
</include>
<where>
<if test="ids != null and ids.size() > 0">
<foreach collection="ids" open="id in ( " close=")" item="uid" separator=",">
#{uid}
</foreach>
</if>
</where>
</select>
SQL语句: select 字段from user where id in (?)
<foreach>标签用于遍历集合,
它的属性: collection:代表要遍历的集合元素,
注意编写时不要写#{}
open:代表语句的开始部分
close:代表结束部分
1. 定义代码片段:
1. sql中可将重复的sql提取出来,使用时用include引用,达到sql语句重用的目的。
<!-- 抽取重复的语句代码片段 -->
<sql id="defaultSql">
select * from user
</sql>
4. 多表查询
1. 一对多
2. 多对多
封装对象的成员变量为对象
<resultMap id="userAccountMap" type="user">
<id column="id" property="id"></id>
<result property="name" column="username" ></result>
<result property="birthday" column="birthday" ></result>
<result property="sex" column="sex" ></result>
<result property="address" column="address" ></result>
<collection property="accounts" ofType="account">
<id property="id" column="aid"></id>
<result property="uid" column="uid" ></result>
<result property="money" column="money" ></result>
</collection>
</resultMap>
<!-- 配置 查询结果的列名和实体类的属性名的对应关系 -->
<resultMap id="accountMap" type="account">
<id property="id" column="aid"></id>
<result property="uid" column="uid" ></result>
<result property="money" column="money" ></result>
<association property="user" javaType="user">
<id column="id" property="id"></id>
<result property="name" column="username" ></result>
<result property="birthday" column="birthday" ></result>
<result property="sex" column="sex" ></result>
<result property="address" column="address" ></result>
</association>
</resultMap>
mybatis 缓冲和注解
1. 加载策略(立即加载/延迟加载)
1. 延迟加载:
1. 概念:在需要数据时才进行加载,不需要时不进行加载。
2. 优点:数据在使用时才进行查询,查询出来的数据少,提高数据库性能,减少内存占用量。
3. 缺点:使用数据时才进行查询,增加查询时间,用户体验差。
2. 立即加载:
1. 注意事项:当打印对象时,将会封装对象的所有属性。将会将延迟加载立即执行。
2. 概念:在调用时将相关的所有数据全部查询出来储存。
3. 开启Mybatis的延迟加载策略
我们需要在Mybatis的配置文件SqlMapConfig.xml文件中添加延迟加载的配置。
<!-- 开启延迟加载的支持 -->
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
4. 使用Collection 实现延迟加载
<!-- collection 是用于建立一对多中集合属性的对应关系
ofType 用于指定集合元素的数据类型
select 是用于指定查询账户的唯一标识(账户的dao 全限定类名加上方法名称)
column 是用于指定使用哪个字段的值作为条件查询
-->
<collection property="accounts" ofType="account"
select="com.itheima.dao.IAccountDao.findByUid"
column="id">
</collection>
<collection>标签:
主要用于加载关联的集合对象
select 属性:
用于指定查询account 列表的sql 语句,所以填写的是该sql 映射的id
column 属性:
用于指定select 属性的sql 语句的参数来源,上面的参数来自于user 的id 列,所以就写成id 这一个字段名了
2. 缓存(一级缓存/二级缓存)
- 什么是缓存?
- 存在于内存中的临时数据
- 为什么使用缓存
- 减少和数据库的交互次数,提高执行效率。
- 什么样的数据能使用缓存,什么样的数据不能使用
- 适用于缓存:
- 经常查询并且不经常改变的。
- 数据的正确与否对最终结果影响不大的。
- 不适用于缓存:
- 经常改变的数据
- 数据的正确与否对最终结果影响很大的。
- Mybatis中的一级缓存和二级缓存
1. 一级缓存(用户级别缓存)是SqlSession 范围的缓存,当SqlSession对象消失时,mybatis的一级缓存也就消失了。当调用SqlSession 的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存。
- 用户级别缓存:用户之间数据不能共享,同一用户可以重复使用。
2. 二级缓存是mapper 映射级别的缓存,多个SqlSession 去操作同一个Mapper 映射的sql 语句,多个SqlSession 可以共用二级缓存,二级缓存是跨SqlSession 的。
- 服务器级别缓存:用户之间可以共享数据。
- 使用步骤:
1. 让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
<settings>
<!-- 开启二级缓存的支持 -->
<setting name="cacheEnabled" value="true"/>
</settings>
因为cacheEnabled的取值默认就为true,所以这一步可以省略不配置。为true代表开启二级缓存;为false代表不开启二级缓存。
2. 让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
<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.itheima.dao.IUserDao">
<!-- 开启二级缓存的支持 -->
<cache></cache>
</mapper>
3. 让当前的操作支持二级缓存(在select标签中配置)
<!-- 根据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,禁用二级缓存。
3. 注解开发Mybatis
1. 当查询结果列字段和封装对象属性值不符合时,可使用 @Results 代替 < resultMap > 标签配置
- @Results({@Result(),@Result()})或@Results(@Result())
@Results(id="userMap",
value= {
@Result(id=true,column="id",property="userId"),
@Result(column="username",property="userName"),
@Result(column="sex",property="userSex"),
@Result(column="address",property="userAddress"),
@Result(column="birthday",property="userBirthday")
})
- @Resutl注解
- 代替了 <id>标签和<result>标签
- @Result 中 属性介绍:
- id 是否是主键字段
- column 数据库的列名
- property需要装配的属性名
- one 需要使用的@One注解(@Result(one=@One)()))
- many 需要使用的@Many注解(@Result(many=@many)()))
2. @One注解(一对一)
- 代替了<assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
- @One注解属性介绍:
- select 指定用来多表查询的sqlmapper
- fetchType会覆盖全局的配置参数lazyLoadingEnabled。
- 使用格式:
- @Result(column=" ",property="",one=@One(select=""))
3. @Many注解(多对一)
- 代替了<Collection>标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。
- 注意:聚集元素用来处理“一对多”的关系。需要指定映射的Java实体类的属性,属性的javaType(一般为ArrayList)但是注解中可以不定义;
- 使用格式:
- @Result(property="",column="",many=@Many(select=""))
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2