一、MyBatis介绍
MyBatis是基于iBatis的一个持久层ORM框架,主要用于实现持久化,将瞬时状态的数据转换为持久状态的过程称为持久化过程,完成持久化的技术比较多,如jdbc(基础操作),ORM框架
ORM:对象关系映射,通过Java对象与数据库关系表的映射实现数据的持久化,在操作数据库时需要使用SQL语句并对结果进行封装,而ORM框架要达到的效果是简化数据库的开发,让数据库操作的过程更加自动化
ORM框架:Hibernate,MyBatis,JPA
Hibernate:是一个完全的ORM框架,在Hibernate中可以不编写任何SQL语句实现对数据库的操作,在使用Hibernate操作时如果需要对SQL语句进行优化,调整则较麻烦,Hibernate的学习成本较高,目前在使用时Hibernate主要集中在项目需求变化不大场景使用
MyBatis:不完全的ORM框架,在MyBatis中需要使用大量的SQL语句来实现数据库操作,由于MyBatis中需要开发人员编写SQL语句,则对SQL的优化、调整变的就极为简单,MyBatis比较适合应用需求变化较多的应用场景,MyBatis学习成本比较低
MyBatis使用步骤:
1.在pom.xml中加入mybatis依赖
2.创建mybatis的核心配置文件(文件名任意)
3.根据表创建对应的实体对象
4.创建操作接口
5.根据操作接口创建Mapper映射文件
6.编写测试类
1.mybatis依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
2.配置MyBatis的核心配置文件
在resources目录下创建mybatis-config.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的核心配置文件-->
<configuration>
<!--
environments:用于配置MyBatis的环境,在其标签体中可以配置多套MyBatis环境
default:用于指定当前应用所使用的mybatis环境
-->
<environments default="development">
<!--
environment:配置一套具体的mybatis环境,一般情况下一个数据库对象一个mybatis环境
id:当前mybatis环境的唯一表示,通过该唯一标识可以获得当前mybatis环境
-->
<environment id="development">
<!--
transactionManager:配置当前所使用的事务管理器
type:指定要使用的事务类型,它执行两种事务类型:
1.JDBC:表示使用jdbc连接进行事务管理
2.MANAGED:表示使用外部容器对事务进行管理(不推荐)
-->
<transactionManager type="JDBC"/>
<!--
dataSource:配置数据源
type:指定数据源类型,包含三种数据源类型:
1.UNPOOLED:不使用数据库连接池方式获取
2.POOLED:使用数据库连接池方式
3.JNDI:由服务器提供的数据源,程序通过JNDI访问外部数据源
-->
<dataSource type="POOLED">
<!--配置数据库及数据库连接池相关属性-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/goods"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--配置SQL映射文件-->
<mappers>
<mapper resource="mapper/GoodsMapper.xml"/>
</mappers>
</configuration>
3.实体对象
public class Goods {
private Integer g_id;
private String g_name;
private Double g_price;
private Date g_date;
public Goods(){
}
//记得生成set get方法 构造方法
}
4.配置映射文件
<?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">
<!--
SQL映射文件,在其中可以配置
1.SQL映射
2.对象与表中字段的映射
3.对象与对象之间的关联映射
namespace:指定当前映射的命名空间(是一个虚拟路径)
为了使用MyBatis的动态代理功能来简化持久层操作,前提条件:
1.namespace的值必须为要操作的Dao接口的完整路径
2.数据库操作标签的id必须为Dao接口中方法的方法名
-->
<mapper namespace="com.jiazhong.Dao.GoodsDao">
<!--
SQL映射
select标签表示查询SQL语句
id:当前SQL映射的唯一表示
resultType:当前SQL语句查询结果中单条数据要封装的Java对象(使用实体类的完整路径名)
parameterType:指定SQL映射中需要的参数(可以省略)
-->
<select id="queryGoods" resultType="com.jiazhong.model.Goods">
select * from tbl_goods
</select>
<!--
当SQL语句中只需要一个参数时,参数名可以任意,通过#{
name}占位符来表示
-->
<select id="queryGoodsById" resultType="com.jiazhong.model.Goods">
select * from tbl_goods where g_id=#{
xxx}
</select>
<insert id="addGoods">
insert into tbl_goods values(default,#{
g_name},#{
g_price},#{
g_date})
</insert>
<update id="updateGoods">
update tbl_goods set g_name=#{
g_name},g_price=#{
g_price},g_date=#{
g_date}
where g_id=#{
g_id}
</update>
<delete id="delGoods">
delete from tbl_goods where g_id=#{
g_id}
</delete>
</mapper>
5.程序实现(在类中加载配置文件)
public class MyBatisTest{
public static void main(String[] args) {
delete();
}
private static void queryGoods() {
//读取配置文件
InputStream inputStream = MyBatisTest2.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
//解析配置文件并生成一个SqlSessionFactory对象(SqlSession工厂对象),该对象中使用工厂模式获得一个一个SqlSession对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//通过sqlSessionFactory对象获得SqlSession对象
//sqlSession对象表示一次关于数据库的会话,其中包含连接对象及MyBatis对数据库操作进行封装的相关方法
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过sqlSession操作数据库
//通过MyBatis动态代理机制获得一个GoodsDao的实现类对象(实现类是一个代理对象不是我们开发)
GoodsDao goodsDao = sqlSession.getMapper(GoodsDao.class );
List<Goods> goodsList = goodsDao.queryGoods();
for (Goods goods : goodsList){
System.out.println(goods);
}
//关闭SqlSession,释放相关资源
sqlSession.close();
}
}
三、MyBatis使用详解
3.1 使用Mapper代理对象进行操作:
使用SqlSession的常用方法如insert、update、delete、selectList、selectOne等方法可以完成数据库的常用操作,但操作不方便,不够直观,所以我们一般使用Mapper映射器的代理对象直接调用mapper映射器中的方法进行操作;
使用mapper代理对象前提条件:
(1)mapper.xml文件中的namespace必须为mapper接口的完整路径
(2)mapper接口中的方法名必须和mapper.xml中每个SQL操作标签的id一致
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.findUser();
3.2 理解SqlSessionFactory和SqlSession
(1) SqlSessionFactory是一个重量级组件,线程安全的,一般情况下一个数据库对应一个SqlSessionFactory对象,所以一般情况下一个应用仅需要一个SqlSessionFactory对象;通过SqlSessionFactory生成SqlSession对象;
//创建SqlSessionFactory对象时默认使用myBatis核心配置文件中的默认环境
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(input);
如果要使用其他的数据库环境则在创建工厂对象时需指定环境
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(input,test);
(2) SqlSession是一个轻量级组件,非线程安全的,该对象通过SqlSessionFactory对象来获得,SqlSession对象我们可以看成一个数据库连接对象。该对象中封装了大量操作数据库的方法;由于SqlSession是非线程安全的,每次使用时要获得一个SqlSession对象,使用结束后关闭该对象;
SqlSessionFactory 有六个方法创建 SqlSession 实例。通常来说,当你选择其中一个方法时,你需要考虑以下几点:
事务处理:你希望在 session 作用域中使用事务作用域,还是使用自动提交(auto-commit)?(对很多数据库和/或 JDBC 驱动来说,等同于关闭事务支持)
数据库连接:你希望 MyBatis 帮你从已配置的数据源获取连接,还是使用自己提供的连接?
语句执行:你希望 MyBatis 复用 PreparedStatement 和/或批量更新语句(包括插入语句和删除语句)吗?
SqlSession openSession()//**默认的,非自动提交事务**
SqlSession openSession(boolean autoCommit)//**自动提交事务**
SqlSession openSession(Connection connection)//**使用自己提供的连接(不适用数据源提供的连接)**
SqlSession openSession(ExecutorType execType)/**/指定处理器类型**
默认的 openSession() 方法没有参数,它会创建具备如下特性的 SqlSession:
事务作用域将会开启(也就是不自动提交)。
将由当前环境配置的 DataSource 实例中获取 Connection 对象。
事务隔离级别将会使用驱动或数据源的默认设置。
预处理语句不会被复用,也不会批量处理更新。
所以我们一般使用openSession(ExecutorType.BATCH)这个方法获取SqlSession对象
你可能对 ExecutorType 参数感到陌生。这个枚举类型定义了三个值:
ExecutorType.SIMPLE:该类型的执行器没有特别的行为。它为每个语句的执行创建一个新的预处理语句。
ExecutorType.REUSE:该类型的执行器会复用预处理语句。
ExecutorType.BATCH:该类型的执行器会批量执行所有更新语句,如果 SELECT 在多个更新中间执行,将在必要时将多条更新语句分
隔开来,以方便理解。
使用SqlSession的常用方法如insert、update、delete、selectList、selectOne等方法可以完成数据库的常用操作,但操作不方便,不够直观,所以我们一般使用Mapper映射器的代理对象直接调用mapper映射器中的方法进行操作;
使用mapper代理对象前提条件:
(1) mapper.xml文件中的namespace必须为mapper接口的完整路径
(2) mapper接口中的方法名必须和mapper.xml中每个SQL操作标签的id一致
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.findUser();
3.3 封装MyBatisUtils类
为了保证SqlSessionFactory在整个应用中只有一个对象,也为了更方便的使用SqlSession对象,我们对SqlSessionFactory对象和SqlSession对象做简单的封装处理。
/***
* 首先在MyBATIS中有三种executor:
* SimpleExecutor -- SIMPLE 就是普通的执行器。
* ReuseExecutor -执行器会重用预处理语句(prepared statements)
* BatchExecutor --它是批量执行器
*/
public class MybatisUtils {
//获得一个SqlSessionFactory对象 这里的参数是主配置文件
private static final SqlSessionFactory FACTORY=creatSqlsessionFactory("Mybatis-config.xml");
private static SqlSessionFactory creatSqlsessionFactory(String config) {
InputStream inputStream = MybatisUtils.class.getClassLoader().getResourceAsStream(config);
return new SqlSessionFactoryBuilder().build(inputStream);
}
public static SqlSession getSqlsession(){
return FACTORY.openSession(ExecutorType.BATCH);
}
}
//以后咱在使用就直接使用类名调getSqlsession方法生成 Sqlsession对象
3.4 映射器传参方式
(1) 如果映射器方法的参数为一个简单参数,占位符参数名可以任意
(2) 如果映射器方法的参数为多个时,占位符参数名按照方法定义参数的顺序依次为arg0,arg1,arg2,……或者param1,param2,param3……
(3) 可以通过@Param注解指定占位参数名
(4) 通过JavaBean传递参数,占位参数名为属性名
(5) #{}与${}的区别
#{}生成的是带有问号占位符的SQL语句
${}生成的是使用连接字符串拼接而成的SQL语句
四、结果映射
MyBatis执行后可以返回的结果可以是基本类型、JavaBean对象、List集合、Map集合等,
结果映射是指将数据库中的列映射到Java对象的相对应的 属性中;
在Mapper.xml中存在两个结果映射:1.resultType 2.resultMap
-
resultType:可以指定基本类型,如int,double,string等也可以指定为自定义对象类型,但要求自定义对象中的属性和数据库查询的列名一致
<?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"> <!-- SQL映射文件,在其中可以配置 1.SQL映射 2.对象与表中字段的映射 3.对象与对象之间的关联映射 namespace:指定当前映射的命名空间(是一个虚拟路径),只是为了实现MyBatis的动态代理功能 一般把namespace设置为Dao接口的路径 --> <mapper namespace="xxx.xxx.com.jiazhong"> <!-- SQL映射 select标签表示查询SQL语句 id:当前SQL映射的唯一表示 resultType:当前SQL语句查询结果中单条数据要封装的Java对象(使用实体类的完整路径名) parameterType:指定SQL映射中需要的参数(可以省略) --> <select id="queryGoods" resultType="com.jiazhong.mybatis.model.Goods"> select * from tbl_goods </select> <!-- 当SQL语句中只需要一个参数时,参数名可以任意,通过#{name}占位符来表示 --> <select id="queryGoodsById" resultType="com.jiazhong.mybatis.model.Goods"> select * from tbl_goods where g_id=#{xxx} </select> <!-- 当SQL映射中需要传入一个自定义对象时,SQL语句中的参数名不能任意,必须为对象的属性名(get方法去掉get字符串并将首字母小写的名字) --> <select id="queryGoodsByIdAndName" parameterType="com.jiazhong.mybatis.model.Goods" resultType="com.jiazhong.mybatis.model.Goods"> select * from tbl_goods where g_id=#{g_id} and g_name like concat('%',#{g_name},'%') </select> </mapper>
-
resultMap:属于高级映射,当Java对象中的属性名和数据库中的列名不一致时,就需要使用resultMap来将数据库中的列映射到Java对象中的属性
resultMap可以继承resultMap,当对象中的属性和表中的字段名一致时可以使用**autoMapping=“true”**实现自动映射
<mapper namespace="com.jiazhong.mybatis.dao.GoodsDao">
<!--
配置结果映射-将表中的字段与类中的属性进行匹配
id:当前结果映射的标识符,唯一标识
type:当前结果映射的类
-->
<resultMap id="goodsMap" type="com.jiazhong.mybatis.model.Goods">
<!--主键映射
column:指定SQL语句中的列名
property:对象中属性名 -->
<id column="id" property="g_id"></id>
<!--普通列映射 -->
<result column="name" property="g_name"></result>
<result column="price" property="g_price"></result>
<result column="date" property="g_date"></result>
</resultMap>
<!--
SQL映射
select标签表示查询SQL语句
id:当前SQL映射的唯一表示
resultType:当前SQL语句查询结果中单条数据要封装的java对象(使用实体类的完整路径名)
parameterType:指定SQL映射中需要的参数(可以省略)
-->
<select id="queryGoods" resultType="goodsMap">
select * from tbl_goods
</select>
</mapper>
五、动态SQL
MyBatis 的强大特性之一便是它的动态SQL,通过MyBatis的动态SQL可以对SQL语句进行灵活拼接操作。
在使用JDBC或其他持久化框架要拼接SQL是件很痛苦的事情,而使用MyBatis则简单的多,MyBatis提供了几个简单的标签来实现动态SQL的拼接;
数据库设计:
if标签:使用if标签根据条件动态拼接SQL
需求:根据商品名称、价格区间、品牌进行综合查询,如果没有选择查询条件则查询全部商品
注意:如图上拼接会出现问题!!!!
注意: 此方式拼接出来的字符串如法将第一个and去掉,如果条件都无法满足时sql语句后面多一个where,会造成SQL语法错误
解决方案:
Where标签:如果标签体中的内容存在自动在SQL语句中添加where关键字,如果where后面第一个关键字是and或or则自动去掉
choose、when、otherwise标签:这三个标签搭配使用,类似java中的switch语句,当在多个条件中只需要其中一个则使用choose标签
价格区间最多只能选择一种,使用choose标签实现:
Set标签:动态更新标签,如果需要根据内容动态更新时使用该标签,该标签会自动在SQL语句中加上set关键字并去掉多余的逗号
需求:根据需要更新表中的内容
Trim标签:自定义标签,该标签可以实现where标签和set标签的功能,主要用于在前缀、后缀增加内容及删除前缀或后缀的内容
Prefix: 设置前缀追加的内容
prefixOverrides: 设置前缀要移除的内容
suffix: 设置后缀要追加的内容
suffixOverrides: 设置后缀要移除的内容
foreach标签:遍历标签,
collection:指定要遍历的集合(数组:array,list:collection|list, set:collection|list,map: parameter)
(item:将集合中的元素赋值给item指定的变量
open:前缀添加内容
close:后缀添加内容
separator:每次循环分割内容)
需求:批量删除
**SQL片段:**为达到SQL语句复用的效果,MyBatis提供SQL片段,SQL片段定义好后可以被多次调用
定义SQL片段:
六、关联映射
关联映射指如何将多个有关联的表映射到对应的关联对象中
对象之间的关联关系是有方向的可以为单向也可以是双向
数据库实例:
用户表:
商品表:
订单明细表:
用户表与商品表:多对多(多对多的关系都是由第三方间接关联)
用户表与订单表:一对多
订单表与用户表:多对一
订单表与明细表:一对多
明细表与订单表:多对一
一对多关联
需求:获得用户的订单,根据用户编号获得该用户及该用户所对应的订单信息
实体对象:在User对象中添加可以存储多个订单的List集合
配置映射文件(通过关联对象查询方式实现):
配置映射文件(通过表连接方式实现):
多对一关联
需求:获得订单及所对应的用户信息(根据订单编号获得订单信息及订单所对应的用户信息)
订单表与用户表:
实体对象:增加关联属性
映射文件:
基于表连接:
多对多关联:
需求:获得用户所购买的商品信息
用户—>订单—>订单明细—>商品
实体类:
用户实体加入订单集合
订单实体加入订单明细集合
订单明细实体加入商品对象
Mapper.java
SQL语句:
Mapper.xml
方式一,在一个xml中配置关联映射
七、延迟加载(LazyLoading)
由于对象之间存在关联,在查询一个对象时MyBatis默认会将其关联对象也查询出来;这无疑增加了数据库的压力,为了降低数据库的压力及提高访问效率,MyBatis对关联映射提供延迟加载(懒加载)策略;
延迟加载是一种按需加载的方式执行数据库查询,根据需要来判断是否查询关联对象
MyBatis中延迟加载是使用多个查询语句实现的
MyBatis默认使用全局立即加载策略,需要我们收到配置某个查询的延迟加载策略,在关联映射中使用fetchType 属性可以配置关联对象的抓取策略(默认为立即加载关联对象, lazy延迟加载)
开启MyBatis的全局延迟加载策略:
根据用户编号获得用户信息,根据需要查询用户订单信息
UserMapper.xml
一般情况下,在一对多关联时,一方使用延迟加载的策略获取关联对象(多方)
在多对一的情况下,多方一般使用立即加载所对应的一方对象(关联对象)
注意:MyBatis中如果使用表连接来查询,则无法使用延迟加载机制
八、MyBatis缓存机制
在MyBatis中为提高查询效率,降低数据库负担,MyBatis提供缓存机制,通过缓存机制降低与数据库的交互次数
MyBatis的缓存有两种:
1.一级缓存(sqlSession级缓存):在同一个sqlSession中起作用,sqlSession一旦关闭,一级缓存消失;
2.二级缓存(mapper级缓存):在同一个mapper中多个sqlSession可以共享的缓存
一级缓存的使用:
一级缓存属于mybatis的默认缓存,默认开启,直接使用
当我们执行查询语句时,mybatis都会将查询的数据存在一级缓存中,直到session关闭或事务提交或手动清空缓存
当执行查询时,mybatis先在一级缓存中查找待查询的数据,如果一级缓存中存在则直接使用不在访问数据库,如果一级缓存中不存在则访问数据库查询,将查询的结果向一级缓存中存储一份,等待后续使用;
当执行commit事务提交时,会自动清空一级缓存中的数据;
二级缓存:
二级缓存脱离sqlSession存在的,而且是同一个mapper共享的,所以默认情况对象并不进入二级缓存,需要手动设置要向二级缓存中存放的对象(一般情况下使用比较频繁的对象放入二级缓存)
在Mapper中通过标签让当前对象存入到二级缓存中
需要存入到二级缓存的对象,必须实现序列化接口
Mybatis中默认开启二级缓存,在需要的mapper(映射器)中配置要缓存的对象即可使用
当查询一个对象时,会现在二级缓存中查找(该对象允许存入到二级缓存中),如果找到则直接返回,如果找不到则在到一级缓存中查找,如果找到则返回,如果招不到会将数据库发送查询请求,并查询相应的数据,将该数据存入到一级缓存和二级缓存(该对象允许存入到二级缓存中),以备后期使用
九、MyBatis注解
注:MyBatis的操作流程:
1.读取核心配置文件
2.创建SqlSessionFactory,是重量级组件,是线程安全的,一个sessionFactory对应一个数据库环境
3.创建SqlSession,轻量级,非线程安全的
4.使用SqlSession进行持久化操作
MyBatis常用注解:
1.@Insert:等同于<insert>定义insert SQL语句
2.@Update:等同于<updatet>定义update SQL语句
3.@Delete: 等同于<delete>定义delete SQL语句
4.@Select: 等同于<select>定义select SQL语句
5.@Results:等于与<resultMap>定义结果映射
6.@Result:等同于<id>和<result>,用于映射属性
6.@ResultMap:用于引用Results定义的结果映射
7.@one:等同于<association>,用于多对一关联中映射单个对象
8.@Many: 等同于<collection>,用于一对多关联中映射多方
需求:
1.根据用户编号获得用户信息及订单信息
2.根据用户编号获得用户信息及订单详情(含购买商品信息)
注解多表连接:
查询所有用户:
public interface IUserDao {
/**
* 查询所有用户
* @return
*/
@Select("select * from user")
@Results(id="userMap",value={
@Result(id=true,column = "id",property = "userId"),
@Result(column = "username",property = "userName"),
@Result(column = "address",property = "userAddress"),
@Result(column = "sex",property = "userSex"),
@Result(column = "birthday",property = "userBirthday"),
@Result(property = "accounts",column = "id",
many = @Many(select = "com.itheima.dao.IAccountDao.findAccountByUid",
fetchType = FetchType.LAZY))
})
List<User> findAll();
}
查询所有账户,并且获取每个账户所属的用户信息:
public interface IAccountDao {
/**
* 查询所有账户,并且获取每个账户所属的用户信息
* @return
*/
@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(property = "user",column = "uid",one=@One(select="com.itheima.dao.IUserDao.findById",fetchType= FetchType.EAGER))
})
List<Account> findAll();
如需帮助 请下方留言