Mybatis
文章目录
一、jdbc初始操作:
1.加载数据库驱动(写死“com.mysql.jdbc.Driver”)
2.通过驱动管理类获取数据库连接
3.定义sql语句,执行
4.释放资源
存在问题:
1.频繁创建数据库连接,释放资源造成系统资源浪费,影响性能;使用连接池可解决
2.Sql语句在代码中写死,实际情况可能会经常改变,不利于维护
二、快速入门:
1.引入jar包/maven坐标
2.编写实体类,编写持久层接口
3.在resource目录下编写持久层接口的映射文件
a.必须.xml,层级目录及名字必须相同
b.mapper 标签的 namespace 属性取值必须是持久层接口的全限定类名
c. 配置文件中的“ #{} ”代表占位符,同“?”;如果参数不是基本类型(对象),#{} 内就要用 #{对象.属性} (ognl 表达式),它会先去找该对象,然后通过其get方法把值取出来,若在 parameterType 属性上指定了实体类名 称,则对象可以省略。
4.编写SqlMapConfig.xml配置文件
<configuration>
<!-- 配置 mybatis 的环境 -->
<environments default="mysql">
<!-- 配置 mysql 的环境 -->
<environment id="mysql">
<!-- 配置事务的类型 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置连接数据库的信息:用的是数据源(连接池) -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ee50"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
</environments>
<!-- 告知 mybatis 映射配置的位置 -->
<mappers>
<mapper resource="com/itheima/dao/IUserDao.xml"/>
</mappers>
</configuration>
5.测试步骤
a.读取SqlMapConfig.xml【InputStream in = Resource.getResourceAsStream(“SqlMapConfig.xml”);】
b.创建SqlSessionFactory构建者对象 【SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();】
c.创建SqlSessionFactory工厂对象 【SqlSessionFactory factory = builder.build(in);】
d.创建SqlSession对象 【SqlSession sqlSession = factory.openSession();】
e.使用SqlSession对象获取dao对象 【Dao dao = sqlSession.getMapper(Dao.class);】
f.调用方法,释放资源
三、#{ } 和 ${ } 的区别
#{ }:相当于一个占位符;可以自动实现java类型和jdbc类型的转换,可以有效防止sql注入问题;若parameterType 传递简单类型值, #{ } 中的值可以任意。
:
可
以
将
p
a
r
a
m
e
t
e
r
T
y
p
e
传
入
的
值
和
s
q
l
语
句
进
行
拼
接
,
不
实
现
j
a
v
a
类
型
和
j
d
b
c
类
型
的
转
换
;
如
果
p
a
r
a
m
e
t
e
r
T
y
p
e
传
输
单
个
简
单
类
型
值
,
{ }:可以将parameterType传入的值和sql语句进行拼接,不实现java类型和jdbc类型的转换;如果 parameterType 传输单个简单类型值,
:可以将parameterType传入的值和sql语句进行拼接,不实现java类型和jdbc类型的转换;如果parameterType传输单个简单类型值,{}括号中只能是 value。
四、传递pojo包装对象(即pojo中包含pojo)
1.编写QueryVo(内涵一个User对象)
2.编写持久层接口
3.编写持久层映射文件
<select id=“findByVo” resultType=“com.itheima.domain.User”
parameterType=“com.itheima.domain.QueryVo”>
select * from user where username like #{user.username};
五、Mybatis的结果集封装
注意: resultType它和 parameterType 一样,如果注册过类型别名的,可以直接使用别名。没有注册过的必须使用 全限定类名。同时,当是实体类名称是,还有一个要求,实体类中的属性名称必须和查询语句中的列名保持 一致,否则无法实现封装。
解决查询列名和实体类属性名不一致方法:
1.sql语句中给列名起别名
2.用resultMap建立列名和属性名的对应关系
<resultMap type="com.itheima.domain.User" id="userMap"> (id唯一标识该resultMap)
<id column="id" property="userId"/> (id标签:指定主键字段)
<result column="username" property="userName"/> (column:列名)
<result column="sex" property="userSex"/> (property:属性名)
<result column="address" property="userAddress"/> (result标签:指定非主键字段)
<result column="birthday" property="userBirthday"/>
</resultMap>
六、SqlMapConfig.xml常用标签
1.-properties(属性) --property
第一种:
<properties>
<property name="jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="jdbc.url" value="jdbc:mysql://localhost:3306/eesy"/>
......
</properties>
第二种:(加载配置文件)
<properties
url = file:///D:/IdeaProjects/day02_eesy_01mybatisCRUD/src/main/resources/jdbcConfig.prop
erties">
</properties>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
2.-typeAliases(类型别名) --typeAliase --package
在 SqlMapConfig.xml 中配置:
<typeAliases>
<!-- 单个别名定义 -->
<typeAlias alias="user" type="com.itheima.domain.User"/>
<!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) -->
<package name="com.itheima.domain"/>
<package name="其它包"/>
</typeAliases>
3.-mappers(映射器) --mapper --package
1.使用相对于类路径的资源
如:<mapper resource="com/itheima/dao/IUserDao.xml" />
2.使用 mapper 接口类路径
如:<mapper class="com.itheima.dao.UserDao"/>
注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。
3.注册指定包下的所有 mapper 接口
如:<package name="com.itheima.dao"/>
注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。
映射文件中会有<mapper namespace="com.itheima.dao.IUserDao">各类sql语句</mapper>与之建立联系
七、Mybatis中数据源(连接池)的配置
1.type=”POOLED”:MyBatis 会创建 PooledDataSource 实例
2.type=”UNPOOLED” : MyBatis 会创建 UnpooledDataSource 实例
3.type=”JNDI”:MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用
**注意:**Mybatis是通过工厂模式创建数据源DataSource对象的,其内部分别定义了实现了 java.sql.DataSource 接口的 UnpooledDataSource, PooledDataSource 类来表示 UNPOOLED、POOLED 类型的数据源
八、Mybatis中的事务控制
Mybatis中的事务提交本质上就是调用JDBC的serAutoCommit()方法来实现事务控制。但是在进行CUD操作过程 中需要我们手动进行事务提交,原因是Mybatis自动默认setAutoCommit()方法值为false。可以在创建session对象时 factory.openSession(true)来使其自动提交。不过还是使用默认false再视情况考虑事务的提交【session.commit()】。
九、Mybatis中动态sql语句
1.sql语句的省略
<sql id = "defaultSql">
select * from user
</sql>
此后在select标签中加入
<include refid="defaultSql"></include>
即可省略相同语句的写入
2. i f 标签:
<select id="findByUser" resultType="user" parameterType="user">
select * from user where 1=1
<if test="username!=null and username != '' ">
and username like #{username}
</if>
<if test="address != null">
and address like #{address}
</if>
</select>
注意:<if>标签的 test 属性中写的是对象的属性名,如果是包装类的对象要使用 OGNL 表达式的写法。
另外要注意 where 1=1 的作用~!
3. where 标签:
<select id="findByUser" resultType="user" parameterType="user">
select * from user
<where>
<if test="username!=null and username != '' ">
and username like #{username}
</if>
<if test="address != null">
and address like #{address}
</if>
</where>
</select>
4. foreach 标签:
<!-- 查询所有用户在 id 的集合之中,queryvo中含有集合ids属性 -->
<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:代表结束部分
item:代表遍历集合的每个元素,生成的变量名
sperator:代表分隔符
十、Mybatis中的多表查询
1.一对一(多对一):
方式一:
创建一个查询结果字段都有的实体类,编写映射文件
<?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.IAccountDao">
<!-- 配置查询所有操作-->
<select id="findAll" resultType="accountuser">
select a.*,u.username,u.address from account a,user u where a.uid =u.id;
</select>
</mapper>
注意:因为上面查询的结果中包含了账户信息同时还包含了用户信息,所以我们的返回值类型 returnType
的值设置为 AccountUser 类型,这样就可以接收账户信息和用户信息了。
方式二:
在多的类中加入一的类,在映射文件中使用resultMap对主表和从表进行一一对应关系
<?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.IAccountDao">
<!-- 建立对应关系 -->
<resultMap type="account" id="accountMap">
<id column="aid" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
<!-- 它是用于指定从表方的引用实体属性的 -->
<association property="user" javaType="user">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<result column="address" property="address"/>
</association>
</resultMap>
<select id="findAll" resultMap="accountMap">
select u.*,a.id as aid,a.uid,a.money from account a,user u where a.uid =u.id;
</select>
</mapper>
2.一对多查询:
在一的类中加入多的类的集合,通过resultMap对两个类中的属性和数据库列名进行一一对应
<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 用于指定集合元素的数据类型-->
<collection property="accounts" ofType="account">
<id column="aid" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
</collection>
</resultMap>
<!-- 配置查询所有操作 -->
<select id="findAll" resultMap="userMap">
select u.*,a.id as aid ,a.uid,a.money from user u left outer join account a on u.id =a.uid
</select>
collection
部分定义了用户关联的账户信息。表示关联查询结果集
property="accounts":
关联查询的结果集存储在 User 对象的上哪个属性。
ofType="account":
指定关联查询的结果集中的对象类型即List中的对象类型。此处可以使用别名,也可以使用全限定名.
3.多对多查询:
需要在两彪之间有一个中间表和中间实体类,中间实体类含有两个类的集合;然后通过resultMap对两个类中的属性 和数据库列名进行一一对应(即同一对多的操作)
<resultMap id="roleMap" type="role">
<id property="roleId" column="rid"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDesc" column="role_desc"></result>
<collection property="users" ofType="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="address" property="address"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
</collection>
</resultMap>
<!--查询所有-->
<select id="findAll" resultMap="roleMap">
select u.*,r.id as rid,r.role_name,r.role_desc from role r
inner join user_role ur on r.id = ur.rid
inner join user u on u.id = ur.uid
</select>
INNER JOIN 内连接 :
内连接就是关联的两张或多张表中,根据关联条件,显示所有匹配的记录,匹配不上的,不显示。
十一、Mybatis的延迟加载
1.延迟加载:
含义:就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.
好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张 表速 度要快。
坏处:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗 时间,所以可能造成用户等待时间变长,造成用户体验下降。
2.使用 assocation 实现延迟加载:
<resultMap type="account" id="accountMap">
<id column="aid" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
<!-- 它是用于指定从表方的引用实体属性的 -->
<association property="user" javaType="user"
select="com.itheima.dao.IUserDao.findById" column="uid">
</association>
</resultMap>
<select id="findAll" resultMap="accountMap">
select * from account
</select>
select: 填写我们要调用的 select 映射的 id
column : 填写我们要传递给 select 映射的参数
在 IUserdDao.xml 和 IUserdDao 中编写方法
<!-- 根据 id 查询 -->
<select id="findById" resultType="user" parameterType="int" >
select * from user where id = #{uid}
</select>
3.使用 Collection 实现延迟加载
<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 property="accounts" ofType="account"
select="com.itheima.dao.IAccountDao.findByUid" column="id">
</collection>
</resultMap>
<!-- 配置查询所有操作 -->
<select id="findAll" resultMap="userMap">
select * from user
</select>
<collection>标签:
主要用于加载关联的集合对象
select 属性:
用于指定查询 account 列表的 sql 语句,所以填写的是该 sql 映射的 id
column 属性:
用于指定 select 属性的 sql 语句的参数来源,上面的参数来自于 user 的 id 列,所以就写成 id 这一个字段名了
在 IAccountDao.xml 和 IAccountDao 中编写方法
<select id="findByUid" resultType="account" parameterType="int">
select * from account where uid = #{uid}
</select>
**注意:**上面两种方式都需要在SqlMapConfig.xml中配置开启延迟加载:
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
十二、Mybatis的缓存:
1.一级缓存:
含义:一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close()等方法 时,就会清空sqlSession的缓存
过程:第一次发起查询操作时,先去找缓存中有该信息,如果没有,从数据库查询信息。 得到信息,将信息存储 到一级缓存中。 如果 sqlSession 去执行 commit 操作(执行插入、更新、删除),就会清空 SqlSession 中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
2.二级缓存:
含义:二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个 SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。
过程:首先开启mybatis的二级缓存
当第一个sqlSession执行查询,查询到的信息会存储到二级缓存中
之后的sqlSession执行相同mapper映射下的sql时,首先会从缓存中查询是否有数据,有则直接取出
若之后的sqlSession执行相同mapper映射下sql,执行commit,将会清空该mapper映射下的二级缓存数据
二级缓存的开启:
第一步:在SqlMapConfig中配置:
<settings>
<!-- 开启二级缓存的支持 -->
<setting name="cacheEnabled" value="true"/>
</settings>
因为 cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为
false 代表不开启二级缓存。
第二步:配置相关mapper映射文件
<?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>
<cache>标签表示当前这个 mapper 映射将使用二级缓存,区分的标准就看 mapper 的 namespace 值。
第三步:配置 statement 上面的 useCache 属性
<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,禁用二级缓存。
十三、Mybatis的常用注解
1.@Results 注解 :
代替的是 标签
@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")
})
2.@One 注解(一对一):
代替的是 标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
属性介绍: select 指定用来多表查询的 sqlmapper
fetchType 会覆盖全局的配置参数lazyLoadingEnabled
使用格式: @Result(column=" “,property=”",one=@One(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.itheima.dao.IUserDao.findById",
fetchType=FetchType.LAZY))
})
3.@Many注解(一对多):
代替的是 标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。
**注意:**聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType (一般为 ArrayList)但是注解中可以不定义。
@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"),
@Result(column="id",property="accounts",
many=@Many(
select="com.itheima.dao.IAccountDao.findByUid",
fetchType=FetchType.LAZY))
})
4.开启二级缓存:
首先还是要在SqlMapConfig.xml中配置开启二级缓存支持;
然后在持久层类上加@CacheNamespace(blocking=true)
@CacheNamespace(blocking=true)//mybatis 基于注解方式实现配置二级缓存
public interface IUserDao {}
Sex"),
@Result(column=“address”,property=“userAddress”),
@Result(column=“birthday”,property=“userBirthday”),
@Result(column=“id”,property=“accounts”,
many=@Many(
select=“com.itheima.dao.IAccountDao.findByUid”,
fetchType=FetchType.LAZY))
})
#### 4.开启二级缓存:
首先还是要在SqlMapConfig.xml中配置开启二级缓存支持;
然后在持久层类上加@CacheNamespace(blocking=true)
@CacheNamespace(blocking=true)//mybatis 基于注解方式实现配置二级缓存
public interface IUserDao {}