文章目录
- 1 MyBatis框架的概述
- 2 MyBatis框架快速入门
- 3 MyBatis框架之dao代理
- 4 MyBatis框架动态SQL
- 5 主配置文件
- 6 PageHelper
1 MyBatis框架的概述
1.1 三层架构
mvc:web开发中,使用mvc架构模式。m:数据 v:视图 c:控制器
- c:控制器:接收请求,调用service对象,显示请求的处理结果。当前使用servlet作为控制器
- v:视图:显示请求的结果的结果,把m中数据显示出来。当前使用jsp,html,css,js等
- m:数据:来自数据库mysql,来自文件,来自网络
mvc作用:
- 实现解耦
- 让mvc各司其职
- 使得系统扩展更好
三层架构:
1.界面层(视图层):接收用户的请求,调用service,显示请求的处理结果。包含了jsp,html,servlet等对象。对应的包controller
2.业务逻辑层:处理业务逻辑,使用算法处理数据的。把数据返回给界面层。对应的是service包,和保重的很多XXXService类。例如:StudentService,OrderSerVice,ShopService
3.持久层(数据访问层):访问数据库,或者是读取文件,访问网络,获取数据。对应的包是dao。dao包中有很多的StudentDao,OrderDao,ShopDao等等
1.2 三层架构请求的处理流程
用户发起请求→界面层→业务逻辑层→持久层→数据库(mysql)
原理图如下:
1.3 为什么要使用三层
1.结构清晰、耦合度低。各层分工明确
2.可维护性高,可扩展性高
3.有利于保准化
4.开发人员可以只关注整个结构中的其中某一层的功能实现
5.有利于各层逻辑的复用
1.4 三层架构模式和框架
每一层对应着一个框架
- 界面层—SpringMVC框架
- 业务层—Spring框架
- 持久层—Mybatis框架
MyBatis框架:
MyBatis是一个优秀的基于java的持久层框架,内部封装了jdbc,开发者只需要关注sql语句本身,而不需要处理加载驱动、创建连接、创建statement、关闭连接
Spring框架:
Spring框架为了解决软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前非常复杂的企业级开发。
SpringMVC框架:
SpringMVC属于SpringFrameWork3.0版本假如的一个模块,为Spring框架提供了构建Web应用程序的能力。
1.5 框架
什么是框架?
框架(Framework)是整个或不分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种认为,框架是可被应用开发者定制的应用模板。
简单的说,框架其实就是半成品软件,就是一组组件,供你使用完成你自己的系统。从另一个角度来说框架时一个舞台,你再舞台上做表演,在框架基础上假如你要完成的功能。
框架时安全的,可复用的,不断升级的软件。
框架是对某一个方面是有用的,不是全能的。
1.6 框架解决的问题
1.框架能实现技术的整合
2.提高开发的效率,降低难度
1.7 jdbc访问数据库的优缺点
优点:
1.直观,好理解
缺点:
- 创建创建很多对象Connection,Statement,ResultSet
- 注册驱动
- 执行sql语句
- 把ResultSet转为Student,List集合
- 关闭资源
- sql语句和业务逻辑代码混为一起
1.8 MyBatis框架
什么是MyBatis?
MyBatis是一个持久层框架,原名是ibatis,2013年改名为MyBatis.
MyBatis可以操作数据库,对数据执行增删改查,看做是高级的JDBC,解决JDBC的缺点
MyBatis可以做什么?
1.注册驱动
2.创建jdbc中使用的Connection,Statement,ResultSet
3.执行sql语句,得到ResultSet
4.处理ResultSet,把记录集中的数据转为java对象,同时还能把java对象放入到List集合
5.关闭资源
6.实现sql语句和java代码的解耦合
2 MyBatis框架快速入门
2.1 使用MyBatis准备
学习文档:
我们按照这个学习路线来学习
在学习此教程之前你需要会这些知识:Java基础,JDBC,Maven
2.2 搭建MyBatis项目八步
2.2.1 创建mysql数据库和表
数据库名:ssm;表名:student
插入一条数据:
2.2.2 在idea中创建一个空项目
然后输入项目名
创建完成之后,我们在里面添加Modules
创建一个Maven项目
输入名字:
一直点next直到创建完成项目,创建完成后我们来查看项目的结构
2.2.3 修改pom.xml文件
1)加入依赖:mybatis依赖,MySQL驱动,junit
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<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.26</version>
</dependency>
2)在加入资源插件
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
2.2.4 创建一个实体类Student
首先创建一个实体包,创建一个Student实体类
定义属性,属性名和列名保持一致
package com.lu.entity;
public class Student {
//属性名和列名保持一致
private Integer id;
private String name;
private String email;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "学生实体信息{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", age=" + age +
'}';
}
}
2.2.5 创建Dao接口,定义操作数据库的方法
创建dao包
代码如下:
package com.lu.dao;
import com.lu.entity.Student;
public interface StudentDao {
//查询一个学生
Student selectStudentById(Integer id);
}
2.2.6 创建xml文件(mapper文件),写sql语句
mybatis框架推荐是把sql语句和java代码分开
mapper文件:定义和dao接口在同一目录,一个表一个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.lu.dao.StudentDao">
<!--查询一个学生Student
<select>:表示查询操作,里面是select语句
id:要执行的sql语句的唯一标识,是一个自定义字符串
推荐使用dao接口中的方法名称
resultType:告诉mybatis,执行sql语句,把数据赋值给哪个类型的Java对象
resultType的值现在使用的Java对象的全限定名称
-->
<select id="selectStudentById" resultType="com.lu.entity.Student">
select id,name,email,age from student where id = 1001
</select>
</mapper>
<!--
1.约束文件
http://mybatis.org/dtd/mybatis-3-mapper.dtd
约束文件的作用:定义和限制当前文件中可以使用的标签和属性,以及标签出现的顺序
2.mapper是根标签
namespace:命名空间,必须有值,不能为空。唯一值
推荐使用Dao接口的全限定名称
作用:参与识别sql语句的作用。
3.在mapper里面可以写 <insert>,<update>,<delete>,<select>等标签
<insert>里面是insert语句,表示执行的是insert操作
<update>里面是update语句,表示执行的是update操作
<delete>里面是delete语句,表示执行的是delete操作
<select>里面是select语句,表示执行的是select操作
-->
2.2.7 创建mybatis的主配置文件(xml文件):只有一个,放在resources目录下
1)定义创建连接实例的数据源(DataSource)对象
2)指定其他mapper文件的位置
<?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">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!--配置数据源:创建Connection对象-->
<dataSource type="POOLED">
<!--driver:驱动的内容-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<!--链接数据库的url-->
<property name="url" value="jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf-8"/>
<!--用户名-->
<property name="username" value="root"/>
<!--密码-->
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--指定其他mapper文件的位置:
指定其他mapper文件目的是找到其他文件的sql语句
-->
<mappers>
<!--
使用mapper的resource属性执行mapper文件的路径
这个路径是从target/classes路径开启的
使用注意:
resource="mapper文件的路径,使用的是 \ 做分隔路径"
一个mapper resource指定一个mapper文件
-->
<mapper resource="com\lu\dao\StudentDao.xml"/>
</mappers>
</configuration>
2.2.8 创建测试的内容
使用main方法,测试mybatis访问数据库
也可以使用junit访问数据库
代码如下:
package com.lu;
import com.lu.entity.Student;
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 org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class MyTest {
//测试mybatis执行sql语句
@Test
public void testSelectStudentById() throws IOException {
//调用mybatis某个对象方法,执行mapper文件中的sql语句
//mybatis的个心累:SqlSessionFactory
//1.定义mybatis主配置文件的位置,从类路径开始的相对路径
String config = "mybatis";
//2.读取主配置文件,使用mybatis框架中的Resources类
InputStream inputStream = Resources.getResourceAsStream(config);
//3.创建SqlSessionFactory对象,使用SqlSessionFactoryBuilder类
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//4.获取SqlSession对象
SqlSession session = factory.openSession();
//5.指定要执行的sql语句的id
// sql语句的id = namespave + "." + select|update|insert|delete标签的id属性值
String sqlId = "com.lu.dao.StudentDao" + "." + "selectStudentById";
//6.通过SqlSession的方法来执行sql语句
Student student = session.selectOne(sqlId);
System.out.println("使用mybatis来查询一个学生:" + student);
//7.关闭SqlSession对象
session.close();
}
}
控制台输出:
到这里我们已经实现了第一个MyBatis的例子
下面我们来修改一下代码,体验一下占位符
2.3 MyBatis使用占位符
我们修改StudentDao.xml文件中select语句
<select id="selectStudentById" resultType="com.lu.entity.Student">
select id,name,email,age from student where id = #{studentId}
</select>
这样我们就使用了占位符,#{}
占位符表示从Java程序中传入过来的数据
我们修改测试代码
Student student = session.selectOne(sqlId, 1001);
重新执行代码,得到一样的输出
2.4 MyBatis使用日志
2.4.1 日志的介绍
我们打开官方教程,看到可以一下几种日志供我们使用
我们来看这一段话
不少应用服务器(如 Tomcat 和 WebShpere)的类路径中已经包含 Commons Logging。注意,在这种配置环境下,MyBatis 会把 Commons Logging 作为日志工具。这就意味着在诸如 WebSphere 的环境中,由于提供了 Commons Logging 的私有实现,你的 Log4J 配置将被忽略。这个时候你就会感觉很郁闷:看起来 MyBatis 将你的 Log4J 配置忽略掉了(其实是因为在这种配置环境下,MyBatis 使用了 Commons Logging 作为日志实现)。如果你的应用部署在一个类路径已经包含 Commons Logging 的环境中,而你又想使用其它日志实现,你可以通过在 MyBatis 配置文件 mybatis-config.xml 里面添加一项 setting 来选择其它日志实现。
这段话的意思也就是或如果我们使用了类似于Tomcat,WebShpere之类的服务器,那么MyBatis会默认使用这些 服务器自带的Commons Logging作为日志工具。而如果我们还想使用其他日志来进行实现,我们必须在主配置文件中添加一项setting来选择其他日志实现。
格式如下:
<configuration>
<settings>
...
<setting name="logImpl" value="LOG4J"/>
...
</settings>
</configuration>
name代表了我们日志的名称,而value的值是我们选择何种日志实现方式
可选的值有:SLF4J、LOG4J、LOG4J2、JDK_LOGGING、COMMONS_LOGGING、STDOUT_LOGGING、NO_LOGGING
我们一般使用的是LOG4J和STDOUT_LOGGING
结合我们昨天学习的东西,我们去mybatis的主配置文件添加以下代码:
<?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">
<configuration>
<!--设置日志-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!--配置数据源:创建Connection对象-->
<dataSource type="POOLED">
<!--driver:驱动的内容-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<!--链接数据库的url-->
<property name="url" value="jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf-8"/>
<!--用户名-->
<property name="username" value="root"/>
<!--密码-->
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--指定其他mapper文件的位置:
指定其他mapper文件目的是找到其他文件的sql语句
-->
<mappers>
<!--
使用mapper的resource属性执行mapper文件的路径
这个路径是从target/classes路径开启的
使用注意:
resource="mapper文件的路径,使用的是 \ 做分隔路径"
一个mapper resource指定一个mapper文件
-->
<mapper resource="com\lu\dao\StudentDao.xml"/>
</mappers>
</configuration>
我们重新来运行代码,执行查询操作
我们可以看到输出的信息比以前更详细了,但出现了几个新的概念。
什么是自动提交?
当你的sql语句执行完毕后,提交事务。数据库更新操作之间保存到数据
什么是手动提交事务?
在你需要提交事务的位置,执行方法,提交事务或者回滚事务
我们下面通过一个添加学生数据的例子,来更清楚的弄懂自动提交和手动提交事务的区别。
2.4.2 添加学生数据
既然我们要添加学生数据,我们首先需要在StudentDao结构中定义一个方法
代码如下:
package com.lu.dao;
import com.lu.entity.Student;
public interface StudentDao {
//查询一个学生
Student selectStudentById(Integer id);
//添加学生
//返回值int,表示本次操作影响的数据库的行数
int insertStudent(Student student);
}
然后在StudentDao.xml文件中来写sql语句
<?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.lu.dao.StudentDao">
<select id="selectStudentById" resultType="com.lu.entity.Student">
select id,name,email,age from student where id = #{studentId}
</select>
<!--添加insert-->
<insert id="insertStudent">
insert into student values(1003,"王五","wangwu@qq.com",18)
</insert>
</mapper>
接下来我们来测试,测试代码如下:
@Test
public void testInsertStudent() throws IOException {
String config = "mybatis";
InputStream inputStream = Resources.getResourceAsStream(config);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = factory.openSession();
String sqlId = "com.lu.dao.StudentDao" + "." + "insertStudent";
int rows = session.insert(sqlId);
System.out.println("使用mybatis添加一个学生,rows = " + rows);
session.close();
}
执行以下:
看控制台我们好像成功了,也返回了rows=1
我们去数据库查看
却没有发现1003王五的数据,这到底是什么回事呢?
我们看划横线的地方,这里关闭了JDBC事务的自动提交
所以原因是mybatis默认执行sql语句是 手动提交事务 的模式,在做insert,update,delete后需要提交事务。
我们再来修改代码
@Test
public void testInsertStudent() throws IOException {
String config = "mybatis";
InputStream inputStream = Resources.getResourceAsStream(config);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = factory.openSession();
String sqlId = "com.lu.dao.StudentDao" + "." + "insertStudent";
int rows = session.insert(sqlId);
session.commit();
System.out.println("使用mybatis添加一个学生,rows = " + rows);
session.close();
}
再来看控制台的输出:
这里多出来了 一行提交JDBC事务,就是我们上面多加的哪一行代码session.commit()
我们再去看数据库,发现数据已经添加上去了
好了,到这里我们这个例子已经成功的搞定了自动提交事务和手动提交事务的区别,那么还有一个问题,就是添加的数据我们是写死的,怎么能够动态的添加的,其实前面我们已经讲了,就是使用占位符
2.4.3 使用占位符
我们来修改StudentDao.xml文件中的insert语句
<!--添加insert
如果传入给mybatis是一个Java对象,使用#{属性名}获取此属性的值
属性值放到 #{} 占位符,mybatis执行此属性对应的getXXX()方法
例如 #{id} 执行的是getId();
-->
<insert id="insertStudent">
insert into student values(#{id},#{name},#{email},#{age})
</insert>
我们来修改测试代码:
@Test
public void testInsertStudent() throws IOException {
String config = "mybatis";
InputStream inputStream = Resources.getResourceAsStream(config);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = factory.openSession();
String sqlId = "com.lu.dao.StudentDao" + "." + "insertStudent";
Student student = new Student();
student.setId(1004);
student.setName("维桑");
student.setEmail("weisang@qq.com");
student.setAge(24);
int rows = session.insert(sqlId, student);
session.commit();
System.out.println("使用mybatis添加一个学生