<一> MyBatis简介
1.什么是ORM?
ORM(Object-RationalMapping),对象关系映射,它的作用是在关系型数据库和对象之间作一个映射处理,JDBC拥有天生的缺陷,需要手动的完成面向对象的java语言、面向关系的数据库之间数据的转换,代码繁琐无技术含量,影响了开发效率。
相当于在面向对象语言和关系数据库之间搭建一个桥梁。这样我们在具体的操作数据库的时候,只要像平时操作对象一样操作它就可以
了,
ORM
框架会根据映射完成对数据库的操作,就不需要再去和复杂的
SQL
语句打交道了。
2.持久化与瞬时状态
- 瞬时状态
当创建一个对象后,但是没有存储到数据库中之前的这一段时间状态被称为瞬时态。
- 持久化状态
当一个对象被存储到了磁盘的数据库中,该种保存状态被称为持久化状态。
3.事务
- 事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新 数据库中各种数据项的一个程序执行单 元(unit)。
- 默认情况下,MySQL的事务提交方式是自动提交。每一条SQL语句就是一个独立的事务!
<二>MyBatis环境搭建
- 下载地址
https://github.com/mybatis/mybatis-3/releases
- 中文文档
https://mybatis.net.cn/
2.1导入依赖
<? xml version = "1.0" encoding = "UTF-8" ?>< project xmlns = "http://maven.apache.org/POM/4.0.0"xmlns : xsi = "http://www.w3.org/2001/XMLSchema-instance"xsi : schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" >< modelVersion > 4.0 . 0 </ modelVersion >< groupId > com . csi </ groupId >< artifactId > mybatis01 </ artifactId >< version > 1.0 - SNAPSHOT </ version >< properties >< maven . compiler . source > 8 </ maven . compiler . source >< maven . compiler . target > 8 </ maven . compiler . target ></ properties >< dependencies ><!-- 添加 mybatis 依赖 -->< dependency >< groupId > org . mybatis </ groupId >< artifactId > mybatis </ artifactId >< version > 3.5 . 7 </ version ></ dependency ><!-- 添加数据库依赖 -->< dependency >< groupId > mysql </ groupId >< artifactId > mysql - connector - java </ artifactId >< version > 8.0 . 23 </ version ></ dependency ><!-- 添加测试依赖 -->< dependency >< groupId > junit </ groupId >< artifactId > junit </ artifactId >< version > 4.12 </ version >< scope > test </ scope ></ dependency >< dependency >< groupId > org . projectlombok </ groupId >< artifactId > lombok </ artifactId >< version > 1.18 . 24 </ version ></ dependency ></ dependencies ></ project >
2.2xml建立
2.2.1全局配置文件
< properties resource = " 属性配置文件的路径 " />< settings >< setting name = "" value = "" /></ settings >< typeAliaes >// 将每一个对应的别名进行分别配置< typeAlias type = " 类 " alias = " 别名 " />// 包扫描< package name = " 实体类包名 " /></ typeAliaes >< configuration >< 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 ></ configuration >
- typeAliaes
- 分别配置
- 使用包扫描
在没有注解的情况下,会使用
JAVABean
的首字母小写的非限定类名来作为它的别名。
<typeAliases> <!--给某一个类做别名--> <!--<typeAlias type="com.csi.smbms.domain.User" alias="User" />--> <!--扫描某一个包,将包中所有类全部自动化命名。规则是将首字母大写!--> <package name="com.csi.domain"/> </typeAliases>
注:所有配置文件都放在resources里
1.具体配置图片
- mybatis-config.xml
如果想要调用
dev
的环境,则需要在
build
的时候,手动添加对应的环境
id
名称
SqlSessionFactory factory = new SqlSessionFactoryBuilder (). build ( is , "dev" ) ;
jdbc:mysql://localhost:3306/smbms?serverTimezone=Asia/Shanghai&zeroDateTimeBehavior=CONVERT_TO_NULL&useAffectedRows=true
- 事务管理(transactionManager)
事务管理默认使用的是JDBC
调用,还可以配置其他
(MANAGED)
的使用方式。
- 数据链接池(dataSource)
默认采用POOLED
,除此外还可以采用
UNPOOLED(
没有连接池,原生
)
以及
JNDI
形式。
- 映射文件加载
配置包扫描的形式,需要注意,要将dao接口类与mapper映射文件放置在同一个包中。
- log4j.properties
- jdbc.properties
2.2.2映射文件
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace: 属性值在全局只能存在一个 , 一般普通写法都是写的对应的实体类名称 --><mapper namespace = "com.csi.domain.Role" ><!--id: 代表方法名称resultType :返回的类型--><select id = "list" resultType = "com.csi.domain.Role" >SELECT * FROM smbms_role</select></mapper>
![](https://i-blog.csdnimg.cn/blog_migrate/97b38328973044ba60305a19e2dc471d.png)
2.2.3日志配置文件
<三>MyBatis的生命周期
3.1 SqlSessionFactoryBuilder
- 用过即丢,其生命周期只存在于方法体内
- 可重用其来创建多个 SqlSessionFactory 实例
- 负责构建SqlSessionFactory,并提供多个build方法的重载
3.2 SqlSessionFactory
- SqlSessionFactory是每个MyBatis应用的核心
- 作用:创建SqlSession实例
- 在创建SqlSession的同时,能够将事务设置为手动的或者是自动的
SqlSession session = sqlSessionFactory.openSession(boolean autoCommit);
autoCommit:
true|false
- 作用域: Application
- 生命周期与应用的生命周期相同
- 单例
存在于整个应用运行时,并且同时只存在一个对象实例
package com . csi . utils ;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 java . io . IOException ;import java . io . InputStream ;public class MyBatisUtil {// 设定一个静态的 SqlSessionFactory 对象private static SqlSessionFactory sqlSessionFactory ;
- 在构建该对象时,就会初始化数据连接池DataSource,当openSqlSession时,会将事务管理器创建出来。
3.3SqlSession
- 包含了执行SQL所需的所有方法
- 对应一次数据库会话,会话结束必须关闭
- 线程级别,不能共享
SqlSession session = sqlSessionFactory . openSession ();try {// do work} finally {session . close ();}
在
SqlSession
里可以执行多次
SQL
语句,但一旦关闭了
SqlSession
就需要重新创建。
在
SqlSession
执行对应的
SQL
语句时,会调用
Executor
执行器执行对应的操作。
4.MyBatisUtils
public class MyBatisUtils {private static ThreadLocal < SqlSession > tl = new ThreadLocal <> () ;private static SqlSessionFactory sessionFactory ;static {InputStream is = null ;try {is = Resources . getResourceAsStream ( "mybatis-cfg.xml" );} catch ( IOException e ) {throw new RuntimeException ( e );}sessionFactory = new SqlSessionFactoryBuilder (). build ( is ) ;}public static SqlSession sqlSession () {SqlSession sqlSession = tl . get ();if ( sqlSession == null ) {sqlSession = sessionFactory . openSession () ;tl . set ( sqlSession );}return sqlSession ;}public static void closeSqlSession () {SqlSession sqlSession = tl . get () ;if ( sqlSession != null ) {sqlSession . close ();tl . set ( null );}}}
5. SELECT
5.1
基本查询
- List: SelectList(namespace+id,参数内容)
- SelectOne:查询一个,SelectOne(namespace+id,参数内容) ;
5.2
模糊查询
- 解决方案:
使用字符串拼接形式
'%${
变量名称
}%'
使用
concat
方式
concat('%',#{
变量名称
},'%')
ps:
代码详见下面
- 多个参数查询
解决方案
:
使用封装对象的形式传输内容
@Testpublic void test2() {SqlSession session = MyBatisUtil.openSession();// 通过 session 获取到接口UserInfoMapper userInfoMapper = session.getMapper(UserInfoMapper.class) ;UserInfo userInfo = new UserInfo() ;userInfo.setUsername("linyuhui");userInfo.setGender(1);userInfo = userInfoMapper.findByManyCondition(userInfo) ;System.out.println(userInfo);session.close();}
UserInfo findByManyCondition(UserInfo userInfo) ;
<select id="findByManyCondition" resultType="userinfo" parameterType="userinfo">SELECT*FROMuserinfoWHEREuserName = #{username} AND gender=#{gender}</select>
- 通过map来进行封装传值
List<Dept> findByCondition(Map<String,Object> map) ;
<select id = "findByCondition" resultType = "dept" parameterType = "map" >SELECT * FROM dept WHERE dname = #{dname} and loc = #{loc}</select>
a.对象查询
VS map
查询
当查询的条件都是来自于同一张表,在前端,通过类似于
Spring MVC
的框架,能够自动实现数据的封装,此时利用对象封装 参数查询就比较方便。
b.当查询的条件都是来自于不同的表内容,那么此时,要么新建立一个临时对象用于作为查询的参数,最好的形式就是
map
来 实现该功能。
- 数据库表中的列名与实体类的字段名不一致
a.解决方案
a-1.通过给列起别名方式解决
SELECT e.*,d .dname as dnmFROMemp e,dept dWHEREe .deptno = d .deptnoANDe .empno = 110111
a-2.通过ResultMap实现字段映射
<!--id : 代表当前 resultMap 的名称type :当前 resultMap 的真实类型id : 主键映射 property = “ 实体类字段 ” column = “ 列名 ”result : 属性映射-->< resultMap id = "emp_result" type = "emp" >< id property = "empno" column = "empno" />< result property = "ename" column = "ename" />< result property = "job" column = "job" />< result property = "hiredate" column = "hiredate" />< result property = "sal" column = "sal" />< result property = "comm" column = "comm" />< result property = "dnm" column = "dname" /></ resultMap >
property:
代表实体类中的字段,会自动映射到对应
column
属性值上,因此
column
字段名称必须要和表中的字段保持一致。
b.
resultType VS resultMap
resultType:
返回的是一个对象。当数据库中的字段与实体类中的属性如果不一致,那么就会导致不一致的属性获取的值是
NULL
。同样,如果在查询较为复杂的情况下,例如多表查询,也无法实现一个一一映射性的关系。
resultMap:
如果查询的结果非常复杂,而且出现了数据库中的字段与实体类中的属性不一致的情况,再有想要实现复杂的关系查
询
(
一对多 多对一等关系
)
时,使用
resultMap
再合适不过了。
以上二者不能够同时存在。
- $与#之间的区别(**)
#{}
是预编译处理,
${}
是字符串替换。
Mybatis
在处理
#{}
时,会将
sql
中的
#{}
替换为
?
号,调用
PreparedStatement
的
set
方法来赋值;
Mybatis
在处理
${}
时,就是把
${}
替换成变量的值。
使用
#{}
可以有效的防止
SQL
注入,提高系统安全性
<select id = "findByLike" resultType = "userinfo" parameterType = "string" >SELECT * FROM smbms_user WHERE userName LIKE '%${str}%'</select><!-- 推荐的形式 --><select id = "findByLike" resultType = "User" parameterType = "String" >SELECT * FROM smbms_user WHERE userName LIKE CONCAT('%',#{userName},'%')</select>
List<UserInfo> findByLike(String userName) ;
@Testpublic void test2() {SqlSession session = MyBatisUtil.openSession();// 通过 session 获取到接口UserInfoMapper userInfoMapper = session.getMapper(UserInfoMapper.class) ;List<UserInfo> like = userInfoMapper.findByLike(" 李 ");System.out.println(like.size());session.close();}
- Mapper接口形式操作
- 接口名称需要与映射配置文件名称相同
- 映射配置文件中namespace必须是接口的全名。
- 接口中的方法名和映射配置文件中的标签的id一致。
- 接口中的返回值类型和映射配置文件中的resultType的指定的类型一致。
- 声明一个接口,将接口与对应的映射文件放置在同一个文件夹中,namespace配置需要引用接口名称,接口中的方法名称与映射文件 中的节点id一致,参数类型、返回值类型一致,在调用时,使用SqlSession对象的getMapper(Mapper.class)的形式调用。
- Mapper接口形式的原理
Dao
接口即
Mapper
接口。接口的全限名,就是映射文件中的
namespace
的值;接口的方法名,就是映射文件中
Mapper
的 Statement的
id
值;接口方法内的参数,就是传递给
sql
的参数。
Mapper
接口是没有实现类的,当调用接口方法时,接口全限名
+
方法名拼接字符串作为
key
值,可唯一定位一个 MapperStatement。