根据动力节点的视频学习后(动力节点MyBatis教程实战精讲(适用于SSM框架初学者课程循序渐进,深入浅出)_哔哩哔哩_bilibili),一点基本总结.
MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。
MyBatis是 MyBatis SQL Mapper Framework for Java (sql映射框架)
1)sql mapper :sql映射
可以把数据库表中的一行数据 映射为 一个java对象。一行数据可以看做是一个java对象。操作这个对象,就相当于操作表中的数据
2) Data Access Objects(DAOs) : 数据访问 , 对数据库执行增删改查。
MyBatis主要类:
(1)Resources 类
Resources 类,顾名思义就是资源,用于读取资源文件。其有很多方法通过加载并解析资源文件,返回不同类型的 IO 流对象。
(2)SqlSessionFactoryBuilder 类
SqlSessionFactory 的 创 建 ,需 要 使 用 SqlSessionFactoryBuilder 对象的build() 方 法 .由 于 SqlSessionFactoryBuilder 对象在创建完工厂对象后,就完成了其历史使命,即可被销毁。所以,一般会将该 SqlSessionFactoryBuilder 对象创建为一个方法内的局部对象,方法结束,对象销毁。
(3)SqlSessionFactory 接口
SqlSessionFactory 接口对象是一个重量级对象(系统开销大的对象),是线程安全的,所以一个应用 只需要一个该对象即可。创建 SqlSession 需要使用 SqlSessionFactory 接口的的 openSession()方法。
➢ openSession(true):创建一个有自动提交功能的 SqlSession
➢ openSession(false):创建一个非自动提交功能的 SqlSession,需手动提交
➢ openSession():同 openSession(false)
(4)SqlSession 接口
SqlSession 接口对象用于执行持久化操作。一个 SqlSession 对应着一次数据库会话,一次会话以 SqlSession 对象的创建开始,以 SqlSession 对象的关闭结束。
SqlSession 接口对象是线程不安全的,所以每次数据库会话结束前,需要马上调用其 close()方法,将 其关闭。再次需要会话,再次创建。 SqlSession 在方法内部创建,使用完毕后关闭。
创建普通java项目
创建项目
在pom.xml中引入依赖
<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>com.oracle.ojdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>19.3.0.0</version>
</dependency>
<!--分页工具-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.10</version>
</dependency>
</dependencies>
添加资源
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/java</directory><!--所在的目录-->
<includes><!--目录下的.properties,.xml 文件都会被扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
添加mybatis的配置文件mybatis.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">
<configuration>
<!--指定properties文件的位置,从类路径开始找文件-->
<properties resource="jdbc.properties" />
<!--settings:控制mybatis全局行为-->
<settings>
<!--设置mybatis输出日志-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--定义别名-->
<typeAliases>
<!--
第一种方式:一次只可以给一个文件定义别名
可以指定一个类型一个自定义别名
type:自定义类型的全限定名称
alias:别名(短小,容易记忆的)
-->
<!-- <typeAlias type="dao.StudentDao" alias="StudentDao"/>-->
<!-- <typeAlias type="domain.Student" alias="Student"/>-->
<!--
第二种方式:
<package> name是包名,这个包中的所有类,类名就是别名(类名不区分大小写)
-->
<package name="domain"/>
</typeAliases>
<!--配置插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"/>
</plugins>
<!--环境配置:数据库的连接信息
default:必须和某个environment的id值一样.
告诉mybatis使用哪个数据库的连接信息
-->
<environments default="development">
<!--environment:一个数据库信息的配置,环境
id:唯一值,自定义,表示环境的名称
-->
<environment id="development">
<!--transactionManager:mybatis的事务类型
type:JDBC(表示使用jdbc中的Connection对象的commit,rollback等事务处理)
-->
<transactionManager type="JDBC"/>
<!--
dataSource:表示数据源,连接数据库的
type:表示数据源的类型,{POOLED表示使用连接池
-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--sql mapper(sql映射文件)的位置-->
<mappers>
<!--第一种方式:一次指定一个文件
一个mapper标签指定一个文件的位置
从类路径开始的路径信息
-->
<!-- <mapper resource="dao/StudentDao.xml"/>-->
<!--第二种方式:一次指定一个目录下的所有文件
使用包名
name:xml文件所在的包名,这个包中的所有xml文件都会加载入mybatis
使用package文件的要求:
1.mapper文件名称需要和接口名称一样,区分大小写
2.mapper文件和dao接口需要在同一目录
-->
<package name="dao"/>
</mappers>
</configuration>
<!--
mybatis的主配置文件:主要定义了数据库的配置信息,SQL映射文件的位置
1.约束文件
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
2.configuration 根标签
-->
添加数据库的信息jdbc.properties,放入资源包中
jdbc.driver=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@localhost:1521:orcl
jdbc.user=system
jdbc.password=password
定义实体类放入domain中
定义操作数据库的dao接口以及映射文件
package dao;
import domain.Student;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface StudentDao {
List<Student> selectStudents();
/*
* 多个参数,使用java对象作为接口中方法的参数
*/
int insertStudents(Student student);
/**
* 多个参数:命名参数,在形参定义的前面加入@Param("自定义参数名称")
*/
List<Student> selectMultiParam(@Param("name") String name,@Param("dept") String dept);
/*
* 多个参数,简单类型的,按位置传值,0,1,2...
* mybatis3.4之前,使用#{0},#{1}...
* mybatis3.4之后,使用#{arg0},#{arg1}...
*/
List<Student> selectMultiParamPosition(String name,String dept);
/**
*多个参数,使用Map存放多个值
*/
List<Student> selectMultiParamMap(Map<String,Object> map);
/**
* 使用${}占位符进行列名或表名的替换
*/
List<Student> selectUse$Order(@Param("type") String type);
//定义方法返回Map
Map<Object,Object> selectMapBySNO(@Param("SNO") Integer SNO);
//使用resultMap
List<Student> selectAllStudent();
//使用列别名
List<Student> selectDiffColProperty();
//第一种模糊查询,在java代码指定 like的内容
List<Student> selectLikeOne(String name);
//第二种方式:在mapper文件中拼接 like的内容
//name就是值,在mapper中拼接like "%"+"王"+"%"
List<Student> selectLikeTwo(String name);
//动态SQL if
List<Student> selectStudentIf(Student student);
//where
List<Student> selectStudentWhere(Student student);
//foreach
List<Student> selectStudentForeach(List<Integer> SNOList);
//使用PageHelper分页数据查询
List<Student> selectAllStudentPage();
}
<?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="dao.StudentDao">
<select id="selectStudents" resultType="domain.Student">
select SNO,SNAME,SSEX,SDEPT from Student order by SNO
</select>
<!--
select:表示查询操作
id:要执行的SQL语法的唯一标识,mybatis会使用这个id的值来找到要执行的SQL语句
可以自定义,但是要求使用接口中的方法名称
resultType:表示结果类型的,是SQL语句执行后得到的ResultSet,遍历这个ResultSet得到java对象的类型
值写的是类型的全限定名称
-->
<!--
多个参数,使用java对象的属性值,作为参数实际值(推荐)
使用对象语法: #{属性名,javaType=类型名称,jdbcType=数据类型} 很少用
javaType:指java中的属性数据类型.
jdbcType:在数据库中的数据类型.
例如: #{paraName,javaType=java.lang.String,jdbcType=VARCHAR}
有简化方式: #{属性名} javaType,jdbcType的值mybatis反射能获取,不用提供
-->
<insert id="insertStudents">
insert into Student (Sno,Sname,Ssex,Sdept) values (#{SNO},#{SNAME},#{SSEX},#{SDEPT})
</insert>
<!--多个参数,使用@Param命名(推荐)-->
<select id="selectMultiParam" resultType="domain.Student">
select SNO,SNAME,SSEX,SDEPT from Student
where SNAME = #{name}
or SDEPT = #{dept}
</select>
<!--多个参数使用位置传参-->
<select id="selectMultiParamPosition" resultType="domain.Student">
select SNO,SNAME,SSEX,SDEPT from Student
where SNAME = #{arg0}
or SDEPT = #{arg1}
</select>
<!--
多个参数使用Map传参
使用语法: #{map的key}
-->
<select id="selectMultiParamMap" resultType="domain.Student">
select SNO,SNAME,SSEX,SDEPT from Student
where SNAME = #{myName}
or SDEPT = #{myDept}
</select>
<!--
使用${}占位符进行列的替换,使可以对排序的类型进行交换
#{}是使用的占位符PreparedStatement
${}是使用字符串连接的方式,使用的是Statement
-->
<select id="selectUse$Order" resultType="Student">
select SNO,SNAME,SSEX,SDEPT from Student
order by ${type}
</select>
<!--返回map
1)列名是map的key,列值是map的value
2)只能最多返回一行记录,多余一行是错误
-->
<select id="selectMapBySNO" resultType="map">
select SNO,SNAME,SSEX,SDEPT from Student
where SNO = ${SNO}
</select>
<!--使用resultMap
1)先定义resultMap
2)在select标签,使用resultMap来引用定义
定义resultMap:
id:自定义名称,表示定义的resultMap
type:java类型的全限定名称
-->
<!--
列名和属性名不一样,第一种方式
使用resultMap
-->
<resultMap id="studentMap" type="domain.Student">
<!--列名和java属性的关系-->
<!--主键使用<id>标签
列使用<result>标签
column:列名
property:java类型的属性名
-->
<id column="SNO" property="SNO"/>
<!--非主键列,使用result-->
<result column="SNAME" property="SNAME"/>
<result column="SSEX" property="SSEX"/>
<result column="SDEPT" property="SDEPT"/>
</resultMap>
<select id="selectAllStudent" resultMap="studentMap">
<include refid="studentSql"/>
</select>
<!--
列名和属性名不一样,第二种方式
resultType的默认原则是 同名的列值赋值给同名的属性
使用列别名(java对象的属性名)
-->
<select id="selectDiffColProperty" resultType="Student">
select SNO as SNO,SNAME as SNAME,SSEX as SSEX,SDEPT as SDEPT from Student
</select>
<!--模糊查询第一种like,java代码指定like的内容-->
<select id="selectLikeOne" resultType="Student">
<include refid="studentSql"/>
where SNAME like #{name}
</select>
<!--模糊查询第二种方式:在mapper文件中拼接 like的内容-->
<select id="selectLikeTwo" resultType="Student">
<include refid="studentSql"/>
where SNAME like '%' || #{name} || '%'
</select>
<!--
动态SQL:sql的内容是变化的,可以根据条件获取到不同的sql语句
主要是where部分发生变化
动态sql的实现,使用的是mybatis提供的标签:
<if>,<where>,<foreach>
-->
<!--
<if>是判断条件的,语法:
<if test="判断java对象的属性值">
部分sql语句
</if>
test:使用参数java对象的属性值作为判断条件
-->
<select id="selectStudentIf" resultType="Student">
<include refid="studentSql"/>
where 1=1
<if test="SNAME!=null and SNAME!=''">
and SNAME = #{SNAME}
</if>
<if test="SSEX!=null and SSEX!=''">
or SSEX = #{SSEX}
</if>
</select>
<!--
<where>是用来包含多个<if>的,当多个if有一个成立的,<where>会自动增加一个where关键字
并自动去掉if中多余的and,or等
-->
<select id="selectStudentWhere" resultType="Student">
<include refid="studentSql"/>
<where>
<if test="SNAME!=null and SNAME!=''">
SNAME = #{SNAME}
</if>
<if test="SSEX!=null and SSEX!=''">
or SSEX = #{SSEX}
</if>
</where>
</select>
<!--
<foreach> 主要循环java中的数组,list集合的
主要用在sql的in语句中
collection:表示接口中的方法参数的类型,如果是数组使用array,如果是list集合使用list
item:自定义的,表示数组和集合成员的变量
open:循环开始时的字符
close:循环结束时的字符
separator:集合成员之间的分隔符
-->
<select id="selectStudentForeach" resultType="Student">
<include refid="studentSql"/>
where SNO in
<foreach collection="list" item="SNOList" open="(" close=")" separator=",">
#{SNOList}
</foreach>
</select>
<select id="selectAllStudentPage" resultType="Student">
<include refid="studentSql"/>
order by SNO
</select>
<!--
创建sql片段
id:片段的自定义名称
引用sql片段:
<include refid="studentSql">
-->
<sql id="studentSql">
select SNO,SNAME,SSEX,SDEPT from Student
</sql>
</mapper>
<!--
SQL映射文件:写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>:表示执行查询
<update>:表示更新数据库的操作
<insert>:表示插入,放的是insert语句
<delete>:表示删除,执行delete语句
-->
在mybatis.xml文件中加入映射信息
<mappers>
<!--第一种方式:一次指定一个文件
一个mapper标签指定一个文件的位置
从类路径开始的路径信息
-->
<!-- <mapper resource="dao/StudentDao.xml"/>-->
<!--第二种方式:一次指定一个目录下的所有文件
使用包名
name:xml文件所在的包名,这个包中的所有xml文件都会加载入mybatis
使用package文件的要求:
1.mapper文件名称需要和接口名称一样,区分大小写
2.mapper文件和dao接口需要在同一目录
-->
<package name="dao"/>
</mappers>
创建工具类MybatisUtil
package 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 {
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(true);//自动提交事务
}
return sqlSession;
}
}
创建测试类测试
package org.example;
import static org.junit.Assert.assertTrue;
import Utils.MybatisUtil;
import com.github.pagehelper.PageHelper;
import dao.StudentDao;
import domain.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;
import java.util.*;
/**
* Unit test for simple App.
*/
public class AppTest
{
/**
* Rigorous Test :-)
*/
// @Test
// public void testInsertStudents() throws IOException {
// //1.定义mybatis主配置文件的名称,从类路径的根开始(target/classes)
// String config= "mybatis.xml";
// //2.读取这个config表示的文件
// InputStream in = Resources.getResourceAsStream(config);
// //3.创建SqlSessionFactoryBuilder对象
// SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// //创建SqlSessionFactory对象
// SqlSessionFactory factory = builder.build(in);
// //5.(重要)获取SqlSession对象,从SqlSessionFactory中获取SqlSession
// SqlSession sqlSession = factory.openSession();
// //6.(重要)指定要执行的SQL语句的表示,用的是SQL映射文件中的namespace+"."+标签的id值
// String sqlID = "dao.StudentDao" + "." + "insertStudents";
// //7.执行SQL语句,通过sqlID找到语句
// Student student = new Student(123,"王旺旺","男","软件学院");
// //8.输出结果
// int num = sqlSession.insert(sqlID,student);
// sqlSession.commit();
// System.out.println("插入了"+num+"条数据");
// //9.关闭SQLSession对象
// sqlSession.close();
// }
@Test
public void testSelectStudents() {
/*
*使用mybatis的动态代理机制,使用SqlSession.getMapper(dao接口)
*getMapper能获取dao接口对应的实现类对象
* */
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
List<Student> students = dao.selectStudents();
students.forEach(student -> System.out.println(student));
}
@Test
public void testInsertStudent(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
Student student = new Student(456,"任人人","男","计算机学院");
int num = dao.insertStudents(student);
System.out.println("插入了"+num+"条数据");
}
@Test
public void testMultiParam(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
List<Student> students = dao.selectMultiParam("张三","软件学院");
students.forEach(student -> System.out.println(student));
}
@Test
public void testMultiParamPosition(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
List<Student> students = dao.selectMultiParamPosition("王二","软件学院");
students.forEach(student -> System.out.println(student));
}
@Test
public void testMultiParamMap(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
Map<String,Object> map = new HashMap<>();
map.put("myName","王二");
map.put("myDept","软件学院");
List<Student> students = dao.selectMultiParamMap(map);
students.forEach(student -> System.out.println(student));
}
@Test
public void testUse$Order(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
// List<Student> students = dao.selectUse$Order("SNO");
// List<Student> students = dao.selectUse$Order("SNAME");
List<Student> students = dao.selectUse$Order("SDEPT");
students.forEach(student -> System.out.println(student));
}
@Test
public void testSelectMap(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
Map<Object,Object> map = dao.selectMapBySNO(223);
System.out.println(map);
}
@Test
public void testSelectResultMap(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
List<Student> students = dao.selectAllStudent();
students.forEach(student -> System.out.println(student));
}
@Test
public void selectDiffColProperty(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
List<Student> students = dao.selectDiffColProperty();
students.forEach(student -> System.out.println(student));
}
@Test
public void selectLikeOne(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
List<Student> students = dao.selectLikeOne("%王%");
students.forEach(student -> System.out.println(student));
}
@Test
public void selectLikeTwo(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
List<Student> students = dao.selectLikeTwo("王");
students.forEach(student -> System.out.println(student));
}
@Test
public void selectStudentIf(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
Student student = new Student();
student.setSNAME("张三");
student.setSSEX("女");
List<Student> students = dao.selectStudentIf(student);
students.forEach(student1 -> System.out.println(student1));
}
@Test
public void selectStudentWhere(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
Student student = new Student();
student.setSNAME("张三");
student.setSSEX("女");
List<Student> students = dao.selectStudentWhere(student);
students.forEach(student1 -> System.out.println(student1));
}
@Test
public void selectStudentForeach(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
List<Integer> SNOList = new ArrayList<>(Arrays.asList(1001,223,224));
List<Student> students = dao.selectStudentForeach(SNOList);
students.forEach(student1 -> System.out.println(student1));
}
@Test
public void selectAllStudentPage(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
//加入PageHelper的方法分页
//pageNum:第几页,从1开始
//pageSize:一页中有多少行数据
PageHelper.startPage(1,3);
List<Student> students = dao.selectAllStudentPage();
students.forEach(student1 -> System.out.println(student1));
}
}