title: Hello-MyBatis
tag: JAVA
1.框架入门 2.What is MyBatis 3.Hello MyBatis 4.Dao 5.动态SQL 6.mybatis配置文件 7.PageHelper插件
1.框架入门
1. 三层架构:
- 界面层:和用户打交道的,接收用户的请求参数,显示处理结果(jsp、html、servlet)
- 业务逻辑层:接收界面层传递的数据,计算逻辑,调用数据库,获取数据
- 数据访问层:访问数据库,对数据进行增删改查
2. 三层架构在项目中对应的包
- 界面层:controller包(servlet)
- 业务逻辑基层:service包(XxxService类)
- 数据访问层:dao包(XxxDao类)
3. 三层中类之间的交互关系
- 界面层–>业务逻辑层–>数据访问层–>数据库
4. 三层架构对应的开发框架
- 界面层:servlet—SpringMVC框架
- 业务逻辑层:service类—spring框架
- 数据访问层:dao类—Mybatis框架
5. 框架是什么
框架是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法,另一种说法;框架是可被应用开发者定制的应用骨架、模板。简单的说,框架其实是半成品软件,就是一组组件,供你使用完成你自己的系统。框架是安全的,可复用的,不断升级的软件
2.What is MyBatis
1. MyBatis是什么
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。
MyBatis提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)
- SQL Mapper:SQL映射,将数据库中的一行数据映射为一个Java对象
- Data Access Objects:数据访问对象,它是对于数据库操作的一种设计方式,把Dao设计为一个通用接口,提供对数据库进行增、删、改、查的一系列操作数据库的抽象方法。
2. MyBatis提供了哪些功能
- 提供了创建Connection、Statement、ResultSet的功能,不用开发人员创建这些对象了
- 提供了执行SQL语句的功能,不用程序员去执行了
- 提供了循环SQL语句的功能,把SQL的执行结果转换为java对象,List集合
- 提供了关闭资源的功能,程序员不用关闭Connection、Statement、ResultSet了
开发人员要做的就是:提供SQL语句,把精力放在写好SQL语句上即可!
3.Hello MyBatis!
- 新建student表
- 加入maven的mybatis依赖和mysql驱动
- 创建实体类 Student- 用来保存表中的一行数据
- 创建持久层的dao接口 定义操作数据库的方法
- 创建mybatis配置文件,叫做sql映射文件,用来写sql语句的。一般一个表一个sql映射文件
- 写在Dao接口所在的目录中
- 文件名称与接口名保持一致
- 创建mybatis的主配置文件,主配置文件提供了数据库的连接信息和sq1映射文件的位置信息
- 创建使用mybatis的类,通过mybatis访问数据库
1. 新建student表
2. 加入maven的mybatis依赖和mysql驱动
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
3. 创建实体类 Student
package xyz.guawaz.domain;
//类名推荐和表名一致,方便记忆
public class Student {
private Integer id;
private String name;
private String email;
private Integer age;
...
}
4. 创建持久层的dao接口 定义操作数据库的方法
public interface StudentDao {
//查询Student表的所有数据
public List<Student> selectStudents();
}
5. 创建mybatis配置文件 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="xyz.guawaz.dao.StudentDao">
<!--
select:表示查询操作
id:要执行的查询操作的唯一标识,mybatis会使用这个id来找到要执行的查询操作
要求使用dao接口中的方法名
resultType:表示结果类型,是sql语句执行后得到的resultSet,遍历这个resultSet得到的java对象的类型
值要求是类型的全限定名称
-->
<select id="selectStudents" resultType="xyz.guawaz.domain.Student">
select id,name,email,age from student order by id
</select>
</mapper>
<!--sq1映射文件:写sq1语句的 ,mybatis会 执行这些sql
1.指定约束文件:
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
2.约束文件的作用:限制、检查在当前文件中出现的标签和格式
3.<mapper:当前文件的根标签,必须的
namespace:命名空间,唯一,要求使用dao接口的全限定名称
4.在当前文件中可以使用特定标签,表示数据库的特定操作
<select>:查询
<update>:更新
<insert>:插入
<delete>:删除
-->
6. 创建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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/guawaz.xyz"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="xyz/guawaz/dao/StudentDao.xml"/>
</mappers>
</configuration>
<!--mybatis的主配置文件,定义了数据库的配置信息和sql映射文件的位置-->
7. 通过mybatis访问数据库
package xyz.guawaz;
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 xyz.guawaz.domain.Student;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLOutput;
import java.util.List;
public class MyApp {
public static void main(String[] args) throws IOException {
//1.定义mybatis主配置文件的名称
String config = "mybatis.xml";
//2.读取这个config表示的文件
InputStream in = Resources.getResourceAsStream(config);
//3.创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//4.创建SqlSessionFactory对象
SqlSessionFactory factory = builder.build(in);
//5.【重要】获取SqlSession对象,从SqlSessionFactory中获取SqlSession
SqlSession sqlSession = factory.openSession();
//6.【重要】指定要执行的sql语句的标识。sql映射文件中的namespace + "." + 标签的id值
String sqlId = "xyz.guawaz.dao.StudentDao" + "." + "selectStudents";
//7.执行sql语句,通过sqlId找到语句
List<Student> studentList = sqlSession.selectList(sqlId);
//8.输出结果
studentList.forEach(stu -> System.out.println(stu));
//9.关闭sqlSession对象
sqlSession.close();
}
}
8. 执行结果
前面我们利用MyBatis实现了对数据库的访问,接下来对这个过程进行优化,更优雅方便地进行数据库访问
4.DAO
1. MyBatis主要类和接口的介绍
- Resources:负责读取主配置文件
- SqlSessionFactoryBuilder:负责创建SqlSessionFactory对象
- SqlSessionFactory接口:默认实现类是DefaultSqlSessionFactory。它是一个重量级对象,程序创建一个对象耗时较长,使用资源较多,整个项目中只需创建一个,它的功能是负责创建SqlSession对象。使用openSession()方法来获取SqlSession对象
- openSession()方法:无参数默认获取非自动提交事务的SqlSession对象。带参数的 openSession(true)获取自动提交事务的SqlSession,openSession(false)获取非自动提交事务的SqlSession
- SqlSession接口:默认实现类是DefaultSqlSession。定义了操作数据库的方法,例如:selectOne(),selectList(),insert(),update(),commit(),roolback()…SqlSession对象不是线程安全的,需要在方法内部使用。在执行sql语句之前使用openSession()获取SqlSession在执行完sql语句后,需要执行SqlSession.close()关闭它,以保证线程安全。
2. 编写MyBatisUtils
package xyz.guawaz.utils;
import com.sun.tools.javac.util.JCDiagnostic;
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 MyBatisUtils {
private static SqlSessionFactory factory = null;
static {
String config = "mybatis.xml";
InputStream in = null;
try {
in = Resources.getResourceAsStream(config);
} catch (IOException e) {
e.printStackTrace();
}
factory = new SqlSessionFactoryBuilder().build(in);
}
//获取sqlSession的方法
public static SqlSession getSqlSession(){
SqlSession sqlSession = null;
if (factory != null){
sqlSession = factory.openSession(); //不自动提交事务,需要手动提交 sqlSession.commit();
}
return sqlSession;
}
}
3. 创建Dao实现类
package xyz.guawaz.dao.impl;
import org.apache.ibatis.session.SqlSession;
import xyz.guawaz.dao.StudentDao;
import xyz.guawaz.domain.Student;
import xyz.guawaz.utils.MyBatisUtils;
import java.util.List;
public class StudentDaoImpl implements StudentDao {
@Override
public List<Student> selectStudents() {
//使用工具类获取SqlSession对象
SqlSession sqlSession = MyBatisUtils.getSqlSession();
//使用SqlSession执行sql语句
List<Student> students = sqlSession.selectList("xyz.guawaz.dao.StudentDao.selectStudents");
//输出结果
students.forEach( stu -> System.out.println(stu));
//关闭SqlSession
sqlSession.close();
return students;
}
@Override
public int insertStudent(Student student) {
//使用工具类获取SqlSession对象
SqlSession sqlSession = MyBatisUtils.getSqlSession();
//使用SqlSession执行sql语句
int num = sqlSession.insert("xyz.guawaz.dao.StudentDao.insertStudent",student);
//提交事务
sqlSession.commit();
//关闭SqlSession
sqlSession.close();
return num;
}
}
这样再操作数据库就可以用Dao实现类对象操作了:
package xyz.guawaz;
import org.junit.Test;
import xyz.guawaz.dao.impl.StudentDaoImpl;
import xyz.guawaz.domain.Student;
import java.util.List;
public class MyTest {
@Test
public void test1(){
StudentDaoImpl studentDao = new StudentDaoImpl();
List<Student> students = studentDao.selectStudents();
}
@Test
public void test2(){
StudentDaoImpl studentDao = new StudentDaoImpl();
Student student = new Student();
student.setId(1008);
student.setName("赵云");
student.setEmail("zhaoyun@qq.com");
student.setAge(25);
int num = studentDao.insertStudent(student);
}
}
4. 使用MyBatis的动态代理,自动创建Dao实现类
public class MyTest {
@Test
public void test(){
/*使用mybatis的动态代理机制,使用SqlSession.getMapper(dao接口)
* 获取dao接口对应的实现类对象
* */
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
List<Student> students = dao.selectStudents();
students.forEach(student -> System.out.println(student));
sqlSession.close();
}
}
5. 传参
传参指的是从Java代码中把实际的值传入mapper文件中
package xyz.guawaz.dao;
import org.apache.ibatis.annotations.Param;
import xyz.guawaz.domain.Student;
import java.util.List;
public interface StudentDao {
/*
* 一个简单类型的参数:
* 简单类型:mybatis把java基本数据类型和String都叫简单数据类型
*
* 在mapper文件获取简单类型的一个参数的值,使用#{任意字符}
*
*多个参数;
* 1.使用@Param命名参数:在形参定义的前面加上@Param("自定义参数名称")
* 在mapper文件使用#{自定义参数名称}获取多个参数的值
* 2.使用对象作为接口中方法的参数
* 在mapper文件使用#{对象的属性名}获取多个参数的值
*
*
* 在mapper文件使用#{}获取参数的值,#也可以换位$
* #和$的区别:
*
* #:使用PreparedStatement执行sql,效率高
* $:使用Statement执行sql,效率低,有sql注入问题
* 在确定数据安全时可以使用$,$可以进行sql拼接,一般用来替换表名、列名等
*
* */
//一个简单类型的参数
Student selectStudentById(Integer id);
//多个参数;
// @Param参数命名
List<Student> selectStudentsByMultiParam(@Param("myname") String name,@Param("myage") Integer age);
//对象方式
List<Student> selectStudentsByObject(Student student);
// # $
List<Student> selectStudentsInOrder(@Param("colName") String colName);
}
<?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="xyz.guawaz.dao.StudentDao">
<!--一个简单类型的参数-->
<select id="selectStudentById" resultType="xyz.guawaz.domain.Student">
select * from student where id=#{sudentId}
</select>
<!--多个参数 @Param参数命名-->
<select id="selectStudentsByMultiParam" resultType="xyz.guawaz.domain.Student">
select id,name,email,age from student where name=#{myname} or age=#{myage}
</select>
<!--多个参数 对象方式-->
<select id="selectStudentsByObject" resultType="xyz.guawaz.domain.Student">
select id,name,email,age from student where name=#{name} or age=#{age}
</select>
<!--$-->
<select id="selectStudentsInOrder" resultType="xyz.guawaz.domain.Student">
select * from student order by ${colName}
</select>
</mapper>
6. 返回类型
<?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="xyz.guawaz.dao.StudentDao">
<!--
resultType:
返回简单类型:
resultType 与dao接口中对应方法的返回值是一致的,可以是int,当查询语句是select count(*)时
返回对象:
resultType 可以是任何一个类,只要查询的值和这个类的属性对应起来就行
返回Map:
resultType="java.lang.HashMap"
1)列名是Map的key,列值是Map的value
2)只能最多返回一行记录 多于一行会报错
resultMap:
解决列名和属性名不一致问题
另一种解决列名和属性名不一致问题的方式:sql语句中为列取别名
-->
<!--返回简单类型-->
<select id="countStudent" resultType="int">
select count(*) from student
</select>
<!--返回对象-->
<select id="selectViewStudent" resultType="xyz.guawaz.vo.ViewStudent">
select id,name from student where name=#{name} or age=#{age}
</select>
<!--返回Map-->
<select id="selectMapById" resultType="java.util.HashMap">
select id,name from student where id=#{id}
</select>
<!--resultMap-->
<resultMap id="myResultMap" type="xyz.guawaz.domain.MyStudent">
<!--主键列-->
<id column="id" property="myId"/>
<!--非主键列-->
<result column="name" property="myName"/>
<result column="email" property="myEmail"/>
<result column="age" property="myAge"/>
</resultMap>
<!--使用resultMap自定义列名和属性的对应关系-->
<select id="selectMyStudent" resultMap="myResultMap">
select * from student
</select>
<!--在sql语句中为列取别名-->
<select id="selectMyStudent2" resultType="xyz.guawaz.domain.MyStudent">
select id as myId,name as myName,email as myEmail,age as myAge from student
</select>
<!--第一种模糊查询 在java代码中指定Like的内容-->
<select id="selectLikeOne" resultType="xyz.guawaz.domain.Student">
select id ,name ,email ,age from student where name like #{name}
</select>
<!--第二种模糊查询 在mapper文件中拼接Like内容-->
<select id="selectLikeTwo" resultType="xyz.guawaz.domain.Student">
select id ,name ,email ,age from student where name like #{name} "%"
</select>
</mapper>
5.动态SQL
动态SQL是指,SQL语句的内容是变化的,可以根据条件获取到不同的SQL语句,主要是where部分发生变化。动态sql的实现,使用的是mybatis提供的标签if/where/foreach
<?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="xyz.guawaz.dao.StudentDao">
<!--
<if>用来判断条件,当条件为真,会把if标签之间的sql加入到主sql之后
-->
<select id="selectStudentIf" resultType="xyz.guawaz.domain.Student">
select id,name,email,age from student
where
<if test="name!=null and name !=''">
name = #{name}
</if>
<if test="age > 0">
or age > #{age}
</if>
</select>
<!--
<where>用来包含多个<if>,当多个if有一个成立的,<where>会自动增加一个where关键字,并去掉if中多余的and or等
-->
<select id="selectStudentWhere" resultType="xyz.guawaz.domain.Student">
select id,name,email,age from student
<where>
<if test="name!=null and name !=''">
name = #{name}
</if>
<if test="age > 0">
or age > #{age}
</if>
</where>
</select>
<!--
<foreach>是用来循环遍历java中的数组、list集合的主要用在sql的in语句中
-->
<!--foreach用法一-->
<select id="selectStudentForOne" resultType="xyz.guawaz.domain.Student">
select * from student where id in
<foreach collection="list" item="myid" open="(" close=")" separator=",">
#{myid}
</foreach>
</select>
<!--foreach用法二-->
<select id="selectStudentForTwo" resultType="xyz.guawaz.domain.Student">
select * from student where id in
<foreach collection="list" item="mystu" open="(" close=")" separator=",">
#{mystu.id}
</foreach>
</select>
<!--sql代码片段,就是复用一些语句
1.先使用sql标签定义代码片段
<sql id=" "> sql语句</sql>
2.再使用<include refid="id的值">引用sql代码片段
-->
<sql id="studentSql">
select id,name,email,age from student
</sql>
</mapper>
6.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>
<!--文件开始位置指定使用数据库属性配置文件jdbc.properties
在 classpath 路径下,创建 properties 文件
使用 key 指定值,语法:${key}
-->
<properties resource="jdbc.properties" />
<!--设置打印日志-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--配置分页插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
<environments default="development">
<environment id="development">
<!--事务管理器,支持两种:JDBC和MANAGED,
JDBC:使用JDBC的事务管理机制。即,通过Connection的commit()方法提交,通过rollback()方法 回滚。
但默认情况下,MyBatis 将自动提交功能关闭了,改为了手动提交。即程序中需要显式的对 事务进行提交或回滚。
MANAGED:由容器来管理事务的整个生命周期(如 Spring 容器)。
-->
<transactionManager type="JDBC"/>
<!--Mybatis 中访问数据库,可以连接池技术,但它采用的是自己的连接池技术。在 Mybatis 的
mybatis.xml配置文件中,通过<dataSource type=”pooled”>来实现 Mybatis 中连接池的配置。
-->
<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>
</environment>
</environments>
<mappers>
<!-- <mapper resource=" " />: 使用相对于类路径的资源,从 classpath 路径查找文件
-->
<!-- <package name=""/>: 指定包下的所有 Dao 接口,注意:此种方法要求 Dao 接口名称和 mapper 映射文件
名称相同,且在同一个目录中。
-->
<mapper resource="xyz/guawaz/dao/StudentDao.xml"/>
</mappers>
</configuration>
<!--mybatis的主配置文件,定义了数据库的配置信息和sql映射文件的位置-->
7.PageHelper插件
1. 加入maven依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.1</version>
</dependency>
2. 在mybatis.xml中加入插件
<!-- 在<environments>之前加入 -->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
3. 使用PageHelper
查询语句之前调用PageHelper.startPage 静态方法,紧跟在这个 方法后的第一个 MyBatis 查询方法会被进行分页。
public void testSelectAll() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
PageHelper.startPage(1,3);//获取第 1 页,3 条内容
List<Student> students = dao.selectAll();
students.forEach(stu -> System.out.println(stu));
sqlSession.close();
}