目录
4.1 创建maven项目,在pom.xml文件中导入Mybatis的坐标
4.2 编写Mybatis核心配置文件 mybatis-config.xml
1.Mybatis框架及ORM
Mybatis官方文档 : mybatis – MyBatis 3 | 简介
1.1 Mybatis框架简介
Mybatis是一个开源的数据持久层框架,它的内部封装了通过了JDBC访问数据库的操作,支持普通的SQL查 询、储存过程和高级映射,几乎消除了所有的JDBC代码和参数的手工设置以及结果集的检索。其主要思想是将SQL 语句剥离出来,配置在配置文件中,实现SQL的灵活配置
1.2 什么是ORM
ORM(Object / Relational Mapping)即对象/关系映射,是一种持久化技术,他在对象模型和关系型数据库之间建 立关系,并且提供SQL映射器机制,通过JavaBean对象去操作数据库表中的数据。MyBatis框架不是一个完整的ORM实现,而是一种半自动化的ORM实现。
1.3 持久化
- 持久化是将程序数据在持久状态和瞬时状态间转换的机制。
- 即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中、XML数据文件中等等。
- JDBC就是一种持久化机制。文件IO也是一种持久化机制。
- 在生活中 : 将鲜肉冷藏,吃的时候再解冻的方法也是。将水果做成罐头的方法也是。
- 为什么需要持久化服务呢?那是由于内存本身的缺陷引起的
- 内存断电后数据会丢失,但有一些对象是无论如何都不能丢失的,比如银行账号等,遗憾的是,人们还无法保证内存永不掉电。
- 内存过于昂贵,与硬盘、光盘等外存相比,内存的价格要高2~3个数量级,而且维持成本也高,至少需要一直供电吧。所以即使对象不需要永久保存,也会因为内存的容量限制不能一直呆在内存中,需要持久化来缓存到外存。
1.4 持久层
- 什么是持久层?
- 完成持久化工作的代码块 . ----> dao层 【DAO (Data Access Object) 数据访问对象】
- 大多数情况下特别是企业级应用,数据持久化往往也就意味着将内存中的数据保存到磁盘上加以固化,而持久化的实现过程则大多通过各种关系数据库来完成。
- 不过这里有一个字需要特别强调,也就是所谓的“层”。对于应用系统而言,数据持久功能大多是必不可少的组成部分。也就是说,我们的系统中,已经天然的具备了“持久层”概念?也许是,但也许实际情况并非如此。之所以要独立出一个“持久层”的概念,而不是“持久模块”,“持久单元”,也就意味着,我们的系统架构中,应该有一个相对独立的逻辑层面,专著于数据持久化逻辑的实现.
- 与系统其他部分相对而言,这个层面应该具有一个较为清晰和严格的逻辑边界。 【说白了就是用来操作数据库存在的!】
1.5 为什么需要Mybatis
- Mybatis就是帮助程序猿将数据存入数据库中 , 和从数据库中取数据 .
- 传统的jdbc操作 , 有很多重复代码块 .比如 : 数据取出时的封装 , 数据库的建立连接等等... , 通过框架可以减少重复代码,提高开发效率 .
- MyBatis 是一个半自动化的ORM框架 (Object Relational Mapping) -->对象关系映射
- 所有的事情,不用Mybatis依旧可以做到,只是用了它,所有实现会更加简单!技术没有高低之分,只有使用这个技术的人有高低之别
1.6 Mybatis框架的优缺点
- Mybatis框架的优点:
- 与直接使用JDBC相比,代码量减少50%以上。
- 简单小巧且易学易用,能够快速上手应用。
- 基于原生SQL,使用灵活,不会对数据库的现有设计产生任何影响。
- SQL语句通过XML文件进行维护,与程序代码解耦,便于统一管理和优化,并可方便地重用。
- 支持编写动态SQL语句,与应用代码解耦。
- 支持Java对象属性与查询结果集字段的映射(ORM)。
- Mybatis框架的缺点:
- SQL语句的编写工作量较大,且对开发人员的SQL使用经验有一定要求。
- 原生SQL语句依赖特定的数据库产品,导致数据库移植性差,不能方便地更换数据库。
- Mybatis框架专注于SQL语句本身,是一个足够灵活的持久化层解决方案。对于需求变化较多丶较频繁,或对性能有一定要求的项目,如互联网项目,Mybatis框架将是一个不错的选择。
2.Mybatis核心对象
2.1 SqlSessionFactoryBuilder
- SqlSessionFactoryBuilder的作用:负责构建SqlSessionFactory(通过读取xml文件和编程构造方式),并且提供多个build()方法的重载
- SqlSessionFactoryBuilder的生命周期和作用域:SqlSessionFactoryBuilder最大特点是:用过即丢。一旦创建SqlSessionFactory对象后,这个类就不需要存在了,因此SqlSessionFactoryBuilder的最佳范围就是存在于方法体,也就是局部变量
2.2 SqlSessionFactory
- SqlSessionFactory的作用:创建SqlSession示例的工厂,通过SqlSessionFactory提供的openSession()方法来获取SqlSession实例。openSession()方法的参数为Boolean值时,若传入true时表示关闭事务管理,自动提交;否则相反。若不传入参数则默认参数为true
- SqlSessionFactory的生命周期和作用域:SqlSessionFactory对象一旦创建,就会在整个应用运行过程中始终存在,没有理由去销毁或在创建它,并且在应用运行过程中也不建议多次创建SqlSessionFactory。因此SqlSessionFactory最佳作用域是Application
2.3 SqlSession
- SqlSession的作用:用于持久化操作的对象,类似于JDBC中的Connection。它提供了面向数据库执行SQL命令所需要的方法,可以通过SqlSession实例直接运行到以映射的SQL语句
- SqlSession的作用域和生命周期:SqlSession对应着一次数据库会话。由于数据库会话不是永久的,因此SqlSession的生命周期也不应该是永久的。相反,在每次访问数据库时都需要创建它,创建SqlSession的地方只有一个,那就是SqlSessionFactory提供的openSession()方法。每个线程都有自己的SqlSession实例,且不能被共享,也不是线程安全的。因此最佳的作用域范围是request作用域或者方法体作用域内。关闭SqlSession非常重要
3.生命周期和作用域
3.1 作用域(Scope)和生命周期
理解我们目前已经讨论过的不同作用域和生命周期类是至关重要的,因为错误的使用会导致非常严重的
并发问题。
我们可以先画一个流程图,分析一下Mybatis的执行过程!
3.2 作用域理解
- SqlSessionFactoryBuilder 的作用在于创建 SqlSessionFactory,创建成功后,SqlSessionFactoryBuilder 就失去了作用,所以它只能存在于创建 SqlSessionFactory 的方法中,而不要让其长期存在。因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
- SqlSessionFactory 可以被认为是一个数据库连接池,它的作用是创建 SqlSession 接口对象。因为 MyBatis 的本质就是 Java 对数据库的操作,所以 SqlSessionFactory 的生命周期存在于整个 MyBatis 的应用之中,所以一旦创建了 SqlSessionFactory,就要长期保存它,直至不再使用 MyBatis 应用,所以可以认为 SqlSessionFactory 的生命周期就等同于 MyBatis 的应用周期。
- 由于 SqlSessionFactory 是一个对数据库的连接池,所以它占据着数据库的连接资源。如果创建多个 SqlSessionFactory,那么就存在多个数据库连接池,这样不利于对数据库资源的控制,也会导致数据库连接资源被消耗光,出现系统宕机等情况,所以尽量避免发生这样的情况。
- 因此在一般的应用中我们往往希望 SqlSessionFactory 作为一个单例,让它在应用中被共享。所以说 SqlSessionFactory 的最佳作用域是应用作用域。
- 如果说 SqlSessionFactory 相当于数据库连接池,那么 SqlSession 就相当于一个数据库连接(Connection 对象),你可以在一个事务里面执行多条 SQL,然后通过它的 commit、rollback 等方法,提交或者回滚事务。所以它应该存活在一个业务请求中,处理完整个请求后,应该关闭这条连接,让它归还给 SqlSessionFactory,否则数据库资源就很快被耗费精光,系统就会瘫痪,所以用 try...catch...finally... 语句来保证其正确关闭。
- 所以 SqlSession 的最佳的作用域是请求或方法作用域,如下(图片):
4. Mybatis环境搭建
4.1 创建maven项目,在pom.xml文件中导入Mybatis的坐标
<?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.bjpowernode</groupId>
<artifactId>ch01-first</artifactId>
<version>1.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>14</maven.compiler.source>
<maven.compiler.target>14</maven.compiler.target>
</properties>
<!--依赖列表-->
<dependencies>
<!--MyBatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<!--资源插件:处理src/main/java目录中的xml-->
<resources>
<resource>
<directory>src/main/java</directory><!--所在的目录-->
<includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
4.2 编写Mybatis核心配置文件 mybatis-config.xml
注意:文件节点有一定顺序,不按照顺序排位会报错
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
注意元素节点的顺序!顺序不对会报错
-->
<!--configuration核心配置文件-->
<configuration>
<!--properties引入外部配置文件-->
<properties resource="database.properties">
<!--优先使用外部配置文件-->
<!--property增加内部配置属性-->
<property name="username" value="root"/>
<property name="password" value="123123"/>
</properties>
<!--给实体类取别名-->
<typeAliases>
<!--typeAlias一条标签对应一个实体类-->
<!-- <typeAlias type="com.hzf.pojo.student" alias="student"/> -->
<!--通过扫描包名来找实体类,对应的实体类的名字首字母建议小写-->
<!--实体类较多时建议使用package-->
<!--可以通过@Alias注解修改实体类名-->
<package name="com.hzf.pojo"/>
</typeAliases>
<!--environments可以配置多套环境-->
<environments default="development">
<environment id="development">
<!--transactionManager事务管理器-->
<transactionManager type="JDBC"/>
<!--dataSource数据源-->
<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>
<!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!-->
<!--mappers映射器-->
<mappers>
<mapper resource="com/hzf/dao/studentMapper.xml"/>
<!--使用下面两种方式必须使用映射器接口实现类的完全限定类名需要配置文件名称和接口名称一致,并且位于同一目录下-->
<!-- <mapper class="com.hzf.dao.studentMapper"/> -->
<!-- <package name="com.hzf.dao"/> -->
</mappers>
</configuration>
4.3 创建实体类
package com.hzf.pojo;
//可以通过注解的方式修改实体类名
//@Alias("ccc")
public class student {
private int Sid;
private String StudentName;
private int Sage;
private String Ssex;
public student() {
}
@Override
public String toString() {
return "student{" +
"Sid=" + Sid +
", StudentName='" + StudentName + '\'' +
", Sage=" + Sage +
", Ssex='" + Ssex + '\'' +
'}';
}
public student(int sid, String studentName, int sage, String ssex) {
Sid = sid;
StudentName = studentName;
Sage = sage;
Ssex = ssex;
}
public int getSid() {
return Sid;
}
public void setSid(int sid) {
Sid = sid;
}
public String getStudentName() {
return StudentName;
}
public void setStudentName(String studentName) {
StudentName = studentName;
}
public int getSage() {
return Sage;
}
public void setSage(int sage) {
Sage = sage;
}
public String getSsex() {
return Ssex;
}
public void setSsex(String ssex) {
Ssex = ssex;
}
}
4.4 创建dao/mapper接口
package com.hzf.dao;
import com.hzf.pojo.student;
import java.util.List;
import java.util.Map;
public interface studentMapper {
/*
* 模糊查询
* */
List<student>getstudentlike(String name);
/*
* 查询全部学生
* */
List<student>getuserlist();
/*
* 查询指定学生
* */
student getuser(int sid);
/*万能的Map应用*/
student getuser2(Map<String,Object> map);
/*
* 增加一个学生
* */
int adduser(student s);
/*
* 修改一个学生
* */
int update(student s);
/*
* 删除一个学生
* */
int deleteuser(int id);
}
4.5 创建SQL映射文件mapper.xml
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace=绑定一个对应的Dao/mapper接口-->
<mapper namespace="com.hzf.dao.studentMapper">
<!--select查询语句-->
<select id="getuserlist" resultType="student">
select * from student
</select>
<!--模糊查询应用-->
<select id="getstudentlike" resultType="student">
select * from student where StudentName like "%"#{name}"%"
</select>
<!--id:对应方法名 parameterType:参数类型 resultType:返回结果类型,如果是int可以不写-->
<select id="getuser" parameterType="int" resultType="student">
select * from student where Sid=#{sid};
</select>
<!--万能的Map应用-->
<select id="getuser2" parameterType="map" resultType="com.hzf.pojo.student">
select * from student where Sid=#{helloid} and Sage=#{sage};
</select>
<!--insert添加语句-->
<insert id="adduser" parameterType="com.hzf.pojo.student">
insert into student (Sid,StudentName,Sage,Ssex) values (#{Sid},#{StudentName},#{Sage},#{Ssex});
</insert>
<!--update修改语句-->
<update id="update" parameterType="com.hzf.pojo.student">
update student set StudentName=#{StudentName},Sage=#{Sage},Ssex=#{Ssex} where Sid=#{Sid};
</update>
<!--delete删除语句-->
<delete id="deleteuser" parameterType="int">
delete from student where Sid=#{id}
</delete>
</mapper>
mapper.xml定义了SQL语句,其中各元素含义如下:
- mapper:映射文件的根元素节点,只有一个属性namespace用于区分不同的mapper,全局唯一
- sql:用于提取多余的SQL语句片段。 只要调用include标签就可以了,refid属性值填sql标签的id属性值
- select:表示查询语句。
- id属性表示该命名空间下唯一标识符
- resultType属性表示SQL语句返回值类型
- parameterType表示传入的参数类型
- 基本数据类型:int,string,long,Date;
- 复杂数据类型:类和Map
4.6 编写测试类
package com.hzf.dao;
import com.hzf.pojo.student;
import com.hzf.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class studentDaoTest {
@Test
/*查询全部学生*/
public void test(){
//第一步:获得SqlSession对象
SqlSession sqlSession= MybatisUtils.getSqlSession();
try{
//方式一:getMapper
//执行sql
studentMapper studentmapper = sqlSession.getMapper(studentMapper.class);
List<student> getuserlist = studentmapper.getuserlist();
for (student student : getuserlist) {
System.out.println(student);
}
// 方式二:selectList已经过时
// List<student> objects = sqlSession.selectList("com.hzf.dao.studentDao.getuserlist");
// for (student student : objects) {
// System.out.println(student);
// }
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭SqlSession
sqlSession.close();
}
}
@Test
/*按学生编号查询*/
public void getusertest(){
//第一步:获得SqlSession对象
SqlSession sqlSession= MybatisUtils.getSqlSession();
try{
//方式一:getMapper
//执行sql
studentMapper studentmapper = sqlSession.getMapper(studentMapper.class);
student getuserlist = studentmapper.getuser(1);
System.out.println(getuserlist);
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭SqlSession
sqlSession.close();
}
}
@Test
/*按学生姓名模糊查询*/
public void getstudentlike(){
//第一步:获得SqlSession对象
SqlSession sqlSession= MybatisUtils.getSqlSession();
try{
//方式一:getMapper
//执行sql
studentMapper studentmapper = sqlSession.getMapper(studentMapper.class);
// List<student> getuserlist = studentmapper.getstudentlike("%A%");
List<student> getuserlist = studentmapper.getstudentlike("A");
for (student student : getuserlist) {
System.out.println(student);
}
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭SqlSession
sqlSession.close();
}
}
@Test
/*万能的map应用*/
public void getusertest2(){
//第一步:获得SqlSession对象
SqlSession sqlSession= MybatisUtils.getSqlSession();
try{
//方式一:getMapper
//执行sql
studentMapper studentmapper = sqlSession.getMapper(studentMapper.class);
Map<String, Object> map = new HashMap<>();
map.put("helloid",4);
map.put("sage",19);
student getuserlist = studentmapper.getuser2(map);
System.out.println(getuserlist);
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭SqlSession
sqlSession.close();
}
}
@Test
/*添加一个学生*/
public void addusertest(){
//第一步:获得SqlSession对象
SqlSession sqlSession= MybatisUtils.getSqlSession();
try{
//方式一:getMapper
//执行sql
studentMapper studentmapper = sqlSession.getMapper(studentMapper.class);
int result = studentmapper.adduser(new student(7,"CC",12,"男"));
sqlSession.commit();
if (result>0){
System.out.println("添加成功!");
}
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭SqlSession
sqlSession.close();
}
}
@Test
/*修改一个学生*/
public void updateusertest(){
//第一步:获得SqlSession对象
SqlSession sqlSession= MybatisUtils.getSqlSession();
try{
//方式一:getMapper
//执行sql
studentMapper studentmapper = sqlSession.getMapper(studentMapper.class);
int result = studentmapper.update(new student(7,"胡闹",15,"女"));
sqlSession.commit();
if (result>0){
System.out.println("修改成功!");
}
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭SqlSession
sqlSession.close();
}
}
@Test
/*删除一个学生*/
public void deleteusertest(){
//第一步:获得SqlSession对象
SqlSession sqlSession= MybatisUtils.getSqlSession();
try{
//方式一:getMapper
//执行sql
studentMapper studentmapper = sqlSession.getMapper(studentMapper.class);
int result = studentmapper.deleteuser(7);
sqlSession.commit();
if (result>0){
System.out.println("删除成功!");
}
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭SqlSession
sqlSession.close();
}
}
}
5.本章总结
- 框架(Framework) 提供了可重用的公共结构,为构建新的应用提供了极大便利。
- 持久化是指将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型。
- ORM (Object Relational Mapping) 即对象/关系映射,是实现域模型和关系模型互相转换的编程技术。
- Mybatis框架的基本要素包括核心接口和类丶核心配置文件丶SQL映射文件。