动力节点—2020最新MyBatis教程笔记
本文为动力节点2020MyBatis笔记整理,视频地址为https://www.bilibili.com/video/BV185411s7Ry?from=search&seid=5830402177484068371。
王鹤老师的笔记可自行去动力节点官网下载。
1 介绍
Java WEB 通常分为三层,即表示层,业务逻辑层,数据访问层。
三层的职责
-
界面层(表示层,视图层):主要功能是接受用户的数据,显示请求的处理结果。使用 web 页面和用户交互,手机 app 也就是表示层的,用户在 app 中操作,业务逻辑在服务器端处理。
-
业务逻辑层:接收表示传递过来的数据,检查数据,计算业务逻辑,调用数据访问层获取数据。
-
数据访问层:与数据库打交道。主要实现对数据的增、删、改、查。将存储在数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库
具体过程为:用户---> 界面层(Spring MVC)--->业务逻辑层(Spring)--->数据访问层(MyBatis)--->DB 数据库。
MyBatis 框架:
MyBatis 是一个优秀的基于 java 的持久层框架,内部封装了 jdbc,开发者只需要关注 sql 语句本身,而不需要处理加载驱动、创建连接、创建 statement、关闭连接,资源等繁杂的过程。
MyBatis 通过 xml 或注解两种方式将要执行的各种 sql 语句配置起来,并通过 java 对象和 sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回。
2 快速入门
对于MyBatis项目来说,除了maven本身的pom.xml以外,还有主配置文件mybatis-config.xml,通常放在Resource目录下;以及各个Dao接口对应的在同级目录下且同名的xml映射文件。在主配置文件中,可以设置数据源,事务,别名,日志,分页以及映射器位置,在Dao对应的映射文件中,通常是写相应的SQL语句来实现Dao的各种功能。
2.1 操作步骤(P9)
2.1.1 首先创建maven
(1)创建maven:New Project/Module->选择Maven,打钩Create from archetype,选择 :maven-archetype-quickstart,next->输入Name/Location,点开Artifact Coordinates,输入相应Id。
(2)等待加载完成后,在src/main上右击,产生resources目录,resources下面的资源在编译后在target/classes下面。
2.1.2 接着会做一些配置
(1)在pom.xml中,修改properties中的1.7为1.8,删除maven原有的build,加入maven的依赖,包括mybatis和mysql驱动,以及一个扫描src/main/java目录下的各种资源放入编译后的target下的classes
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory><!--所在的目录-->
<includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
(2)创建Dao接口以及涉及到的Bean对象
(3)创建mapper文件,也叫sql映射文件,是一个xml:写sql语句的,和接口中方法对应的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.bjpowernode.dao.StudentDao">
<!--
select:表示查询操作。
id: 你要执行的sql语法的唯一标识, mybatis会使用这个id的值来找到要执行的sql语句
可以自定义,但是要求你使用接口中的方法名称。
resultType:表示结果类型的, 是sql语句执行后得到ResultSet,遍历这个ResultSet得到java对象的类型。
值写的类型的全限定名称
-->
<select id="selectStudents" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student order by id
</select>
<!--插入操作-->
<insert id="insertStudent">
insert into student values(#{id},#{name},#{email},#{age})
</insert>
</mapper>
<!--
sql映射文件(sql mapper): 写sql语句的, mybatis会执行这些sql
1.指定约束文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
mybatis-3-mapper.dtd是约束文件的名称, 扩展名是dtd的。
2.约束文件作用: 限制,检查在当前文件中出现的标签,属性必须符合mybatis的要求。
3.mapper 是当前文件的根标签,必须的。
namespace:叫做命名空间,唯一值的, 可以是自定义的字符串。
要求你使用dao接口的全限定名称。
4.在当前文件中,可以使用特定的标签,表示数据库的特定操作。
<select>:表示执行查询,select语句
<update>:表示更新数据库的操作, 就是在<update>标签中 写的是update sql语句
<insert>:表示插入, 放的是insert语句
<delete>:表示删除, 执行的delete语句
-->
(4)创建mybatis的一个主配置文件,也是xml,放在resources下,1)连接数据库;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>
<!--settings:控制mybatis全局行为-->
<settings>
<!--设置mybatis输出日志-->
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
<!--环境配置: 数据库的连接信息
default:必须和某个environment的id值一样。
告诉mybatis使用哪个数据库的连接信息。也就是访问哪个数据库
-->
<environments default="mydev">
<!-- environment : 一个数据库信息的配置, 环境
id:一个唯一值,自定义,表示环境的名称。
-->
<environment id="mydev">
<!--
transactionManager :mybatis的事务类型
type: JDBC(表示使用jdbc中的Connection对象的commit,rollback做事务处理)
-->
<transactionManager type="JDBC"/>
<!--
dataSource:表示数据源,连接数据库的
type:表示数据源的类型, POOLED表示使用连接池
-->
<dataSource type="POOLED">
<!--
driver, user, username, password 是固定的,不能自定义。
-->
<!--数据库的驱动类名-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--连接数据库的url字符串-->
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<!--访问数据库的用户名-->
<property name="username" value="root"/>
<!--密码-->
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- sql mapper(sql映射文件)的位置-->
<mappers>
<!--一个mapper标签指定一个文件的位置。
从类路径开始的路径信息。 target/clasess(类路径)
-->
<mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
<!--<mapper resource="com/bjpowernode/dao/SchoolDao.xml" />-->
</mappers>
</configuration>
<!--
mybatis的主配置文件: 主要定义了数据库的配置信息, sql映射文件的位置
1. 约束文件
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
mybatis-3-config.dtd:约束文件的名称
2. configuration 根标签。
-->
(5)使用mybatis的对象SqlSession,通过他的方法执行sql语句。
@Test
public void testSelect() throws Exception{
//1.mybatis 主配置文件
String config = "mybatis-config.xml";
//2.读取配置文件
InputStream in = Resources.getResourceAsStream(config);
//3.创建 SqlSessionFactory 对象,目的是获取 SqlSession
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//4.获取 SqlSession,SqlSession 能执行 sql 语句
SqlSession session = factory.openSession();
//5.执行 SqlSession 的 selectList()
List<Student> studentList = session.selectList("com.bjpowernode.dao.StudentDao.selectStudents");
//6.循环输出查询结果
studentList.forEach( student -> System.out.println(student));
//7.关闭 SqlSession,释放资源
session.close();
}
2.2 在编译的target目录下面缺少xml的解决方式(P11)
事先做的配置
1.resource文件夹,前面需要有相应的标识,没有的话,右键-Mark Directory as
2.在pom.xml文件中的<build><resources>...</resources></build>放置resource,用于扫描并将src/main/java的相应资源导入。(见操作步骤)
解决方式
1.右边的maven,先clean,然后compile
2.上面的Build-ReBuild Project
3.上边的File-Invalidate Caches/Restart,再点一次。
4.将sql映射文件和主配置文件直接拷贝到target目录下面。
2.3 日志的输出
在mybatis.xml的<configuration>后面添加
<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
2.4 注意事项
mybatis默认非自动提交事务,查询不需要提交,而insert/update/delete,需要提交,sqlSession.commit();
2.5对各个对象的分析
Resource类
Resources 类,顾名思义就是资源,用于读取资源文件。其有很多方法通过加载并解析资源文件,返回不同类型的 IO 流对象。
SqlSessionFactoryBuilder类
SqlSessionFactory 的 创 建 , 需 要 使 用 SqlSessionFactoryBuilder 对 象 的 build() 方 法 。 由于SqlSessionFactoryBuilder 对象在创建完工厂对象后,就完成了其历史使命,即可被销毁。所以,一般会将该 SqlSessionFactoryBuilder 对象创建为一个方法内的局部对象,方法结束,对象销毁。
SqlSessionFactory接口
SqlSessionFactory 接口对象是一个重量级对象(系统开销大的对象),是线程安全的,所以一个应用只需要一个该对象即可。创建 SqlSession 需要使用 SqlSessionFactory 接口的的 openSession()方法。
➢ openSession(true):创建一个有自动提交功能的 SqlSession
➢ openSession(false):创建一个非自动提交功能的 SqlSession,需手动提交
➢ openSession():同 openSession(false)
SqlSession接口
SqlSession 接口对象用于执行持久化操作。一个 SqlSession 对应着一次数据库会话,一次会话以SqlSession 对象的创建开始,以 SqlSession 对象的关闭结束。
SqlSession 接口对象是线程不安全的,所以每次数据库会话结束前,需要马上调用其 close()方法,将其关闭。再次需要会话,再次创建。 SqlSession 在方法内部创建,使用完毕后关闭。
2.6 工具类
通过该工具类的静态方法可以方便获取SqlSession。
public class MyBatisUtils {
private static SqlSessionFactory factory = null;
static {
String config="mybatis.xml"; // 需要和你的项目中的文件名一样
try {
InputStream in = Resources.getResourceAsStream(config);
//创建SqlSessionFactory对象,使用SqlSessionFactoryBuild
factory = new SqlSessionFactoryBuilder().build(in);
} catch (IOException e) {
e.printStackTrace();
}
}
//获取SqlSession的方法
public static SqlSession getSqlSession() {
SqlSession sqlSession = null;
if( factory != null){
sqlSession = factory.openSession();// 非自动提交事务
}
return sqlSession;
}
}
3 MyBatis DAO代理
3.1两种sql的执行方式
第一类是前面的方法,SqlSession直接执行selectList/update/delete/insert之类操作;
第二类是先通过SqlSession的getMapper()获取接口Dao的实现类,然后调用接口的方法。原理是动态代理。
以select为例解释,第一种是通过SqlSession直接执行selectList来获取数据,第二种是SqlSession首先获取一个StudentDao的一个实现类,该实现类可以直接调用selectStudents获取数据。
SqlSession session = MyBatisUtil.getSqlSession();
List<Student> studentList = session.selectList("com.bjpowernode.dao.StudentDao.selectStudents");
StudentDao studentDao = MyBatisUtil.getSqlSession().getMapper(StudentDao.class);
List<Student> studentList = studentDao.selectStudents();
3.2 参数的理解
3.2.1 parameterType
parameterType表示传入的参数类型,可以省略。
3.2.2 传入的参数在SQL语句中的使用
(1)如果传入的是一个简单类型(java 基本类型和 String),在SQL中,可以用#{任意字符}
<select id="selectById" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where id=#{studentId}
</select>
#{studentId} , studentId 是自定义的变量名称,和方法参数名无关。
(2)传入多个参数,使用@Param
接口方法:
List<Student> selectMultiParam(@Param("personName") String name,@Param("personAge") int age);
mapper 文件:
<select id="selectMultiParam" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name=#{personName} or age
=#{personAge}</select>
(3)传入一个对象,#{ property,javaType=java 中数据类型名,jdbcType=数据类型名称 },简写为 #{ property }
创建保存参数值的对象 QueryParam
package com.bjpowernode.vo;
public class QueryParam {
private String queryName;
private int queryAge;
//set ,get 方法}
接口方法:
List<Student> selectMultiObject(QueryParam queryParam);
mapper 文件:
<select id="selectMultiObject" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name=#{queryName} or age
=#{queryAge}
</select>
(4)多个参数还可以按位置或者使用map
3.2.3 #和$的区别
1. #使用 ?在sql语句中做占位的, 使用PreparedStatement执行sql,效率高
2. #能够避免sql注入,更安全。
3. $不使用占位符,是字符串连接方式,使用Statement对象执行sql,效率低
4. $有sql注入的风险,缺乏安全性。
5. $:可以替换表名或者列名
3.2.4 resultType和resultMap
两者选一,resultMap主要用于表的列和对象属性不匹配。
<resultMap id="student2Map" type="com.bjpowernode.domain.Student2">
<!-- 主键字段使用 id -->
<id column="id" property="id2" />
<!--非主键字段使用 result-->
<result column="name" property="name2"/>
<result column="email" property="email2" />
<result column="age" property="age2" />
</resultMap>
<select id="selectStudents2" resultMap="student2Map">
select id,name,email,age from student order by id
</select>
3.2.5 模糊like
例 1: java 代码中提供要查询的 “%力%”
接口方法:
List<Student> selectLikeFirst(String name);
mapper 文件:
<select id="selectLikeFirst" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student
where name like #{studentName}
</select>
测试方法:
@Test
public void testSelectLikeOne(){
String name="%力%";
List<Student> stuList = studentDao.selectLikeFirst(name);
stuList.forEach( stu -> System.out.println(stu));
}
例 2:mapper 文件中使用 like name "%" #{xxx} "%"
接口方法:
List<Student> selectLikeSecond(String name);
mapper 文件:
<select id="selectLikeSecond" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student
where name like "%" #{studentName} "%"
</select>
测试方法:
@Test
public void testSelectLikeSecond(){
String name="力";
List<Student> stuList = studentDao.selectLikeSecond(name);
stuList.forEach( stu -> System.out.println(stu));
}
4 动态SQL
对于 sql 中的"<",一定要换成"<"。
动态 SQL 相当于会变化的 SQL,主要包括<if>,<where>,<foreach>和代码片段。
if 可以在满足条件时执行相应功能,where主要用于包装if,去掉多余的and/or,foreach是对于一个可以遍历的集合进行输出,代码片段表示代码的重用功能。
示例:
4.1 if 和 where
<select id="selectStudentWhere" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student
<where>
<if test="name != null and name !='' ">
and name = #{name}
</if>
<if test="age > 0 ">
and age > #{age}
</if>
</where>
</select>
4.2 foreach
<!--说明-->
<foreach collection="集合类型" open="开始的字符" close="结束的字符"
item="集合中的成员" separator="集合成员之间的分隔符">
#{item 的值}
</foreach>
<!--示例-->
<select id="selectStudentForList"
resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student
<if test="list !=null and list.size > 0 ">
where id in
<foreach collection="list" open="(" close=")"
item="stuid" separator=",">
#{stuid}
</foreach>
</if>
</select>
4.3 代码片段,重用
<sql/>标签用于定义 SQL 片断,以便其它 SQL 标签复用。而其它标签使用该 SQL 片断,需要使用<include/>子标签。
<sql id="studentSql">
select id,name,email,age from student
</sql> <select id="selectStudentSqlFragment"
resultType="com.bjpowernode.domain.Student">
<!-- 引用 sql 片段 -->
<include refid="studentSql"/>
<if test="list !=null and list.size > 0 ">
where id in
<foreach collection="list" open="(" close=")"
item="stuobject" separator=",">
#{stuobject.id}
</foreach>
</if>
</select>
5 配置文件
5.1 主配置文件
之前项目中使用的 mybatis.xml 是主配置文件。
主配置文件特点:
1.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">
2.根元素,<configuration>
3.主要包含内容:
定义别名
数据源
mapper 文件
5.2 dataSource
在主配置文件中配置,包括下面三种
-
UNPOOLED 不使用连接池的数据源,MyBatis 会创建 UnpooledDataSource 实例
-
POOLED 使用连接池的数据源,MyBatis 会创建 PooledDataSource 实例
-
JNDI 使用 JNDI 实现的数据源,MyBatis 会从 JNDI 服务上查找 DataSource 实例
<dataSource type="POOLED">
<!--连接数据库的四个要素-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/ssm?charset=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
5.3 事务
使用位置,<transactionManager type="JDBC"/>
-
JDBC,使用 JDBC 的事务管理机制。默认不自动提交,需要手动提交。
-
MANAGED,由容器来管理事务的整个生命周期(如 Spring 容器)。
5.4 使用数据库属性配置文件
将写在dataSource中数据库四个要素抽取到一个文件中,主文件中换成${文件名.具体name}。
<dataSource type="POOLED">
<!--使用 properties 文件: 语法 ${key}-->
<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>
5.5 mapper(映射器)
1.<mapper resource=" " />
使用相对于类路径的资源,从 classpath 路径查找文件,
例如:<mapper resource="com/bjpowernode/dao/StudentDao.xml" />
2. <package name=""/>
指定包下的所有 Dao 接口
如:<package name="com.bjpowernode.dao"/>
注意:此种方法要求 Dao 接口名称和 mapper 映射文件名称相同,且在同一个目录中。
6 分页
使用插件 PageHelper,对应配置如下:
- 在pom.xml中
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.10</version>
</dependency>
- 在mybatis主配置文件中,<environments>之前加入
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor" />
</plugins>
用法
@Test
public void testSelect() throws IOException {
//获取第 1 页,3 条内容
PageHelper.startPage(1,3);
List<Student> studentList = studentDao.selectStudents();
studentList.forEach( stu -> System.out.println(stu));
}