MyBatis学习笔记
MyBatis官方文档
目录- 1.框架概述
- 1.1 目前一般采用以下三层架构
- 1.2 三层中各个类的交互方式
- 1.3 三层对应的处理框架
- 1.4 三个框架简介
- 1.5 MyBatis功能
- 2.MyBatis框架快速入门
- 2.1 MyBatis查询数据库操作
- 2.2 MyBatis Insert操作(使用动态代理)
- 3.MyBatis框架Dao代理(※)
- 3.1 实现步骤
- 3.2 实现原理
- 3.3 MyBatis相关参数的理解
- (1)parameterType
- (2)@Param命名参数
- 3.4 #和$的区别
- 3.5 MyBatis的输出结果
- (1) resultType
- (2) resultMap
- 3.6 like模糊查询
- 4.MyBatis框架动态SQL(※)
- 4.1 if 标签
- 4.2 where标签
- 4.3 foreach标签
- 遍历List<简单类型>
- 遍历List<对象类型>
- 4.4 sql标签
- 5.MyBatis配置文件(了解)
- 5.1 主配置文件
- 属性配置文件的书写
- 5.2 sql映射文件
- 5.1 主配置文件
1.框架概述
MVC模式(Model–view–controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。
1.1 目前一般采用以下三层架构
- 界面层: 和用户打交道的, 接收用户的请求参数, 显示处理结果的。在实现代码中,界面层的代码一般放置于controller包中。
- 业务逻辑层: 接收了界面层传递的数据,计算逻辑,调用数据库,获取数据。在实现代码中,业务逻辑层的代码一般放置于service包中(XXXService类)。
- 数据访问层(持久层): 就是访问数据库, 执行对数据的查询,修改,删除等等的。在实现代码中,数据访问层的代码一般放置于dao包中(XXXDao类)。
1.2 三层中各个类的交互方式
用户使用界面层 --> 业务逻辑层 ---> 数据访问层(持久层)--> 数据库(mysql)
1.3 三层对应的处理框架
- 界面层---springmvc(框架)
- 业务逻辑层---service类--spring(框架)
- 数据访问层---dao类--mybatis(框架)
这三层对应的框架便是非常著名的SSM三件套。利用SpringMVC接收用户请求,响应结果。利用Spring管理service类。利用mybatis代替jdbc访问数据库,所以mybatis可以看成是功能更加完善的jdbc。
1.4 三个框架简介
MyBatis框架:
MyBatis是一个优秀的基于java的持久层框架,内部封装了jdbc,开发者只需要关注sql语句本身,而不需要处理加载驱动、创建连接、创建statement、关闭连接,资源等繁杂的过程。MyBatis通过xml或注解两种方式将要执行的各种sql语句配置起来,并通过java对象和sql的动态参数进行映射生成最终执行的sql语句,最后由 mybatis框架执行sql并将结果映射为java对象并返回。开发人员使用MyBatis的流程如下:
开发人员提供sql语句 ---> mybatis处理sql ---> 开发人员得到List集合或java对象(表中的数据)
Spring框架:
Spring框架为了解决软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前非常复杂的企业级开发。Spring解决了业务对象,功能模块之间的耦合,不仅在javase,web中使用,大部分Java应用都可以从Spring中受益。Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器。
SpringMVC框架
SpringMVC属于SpringFrameWork 3.0 版本加入的一个模块,为Spring框架提供了构建Web应用程序的能力。现在可以Spring框架提供的SpringMVC模块实现web应用开发,在web项目中可以无缝使用Spring和SpringMVC框架。
1.5 MyBatis功能
MyBatis是一个sql映射框架,提供对数据库的操作能力。可以理解为是增强的JDBC。其主要有两个功能
sql mapper:sql映射功能,可以把数据库表中的一行数据映射为一个java对象。操作这个对象,就相当于操作表中的数据Data Access Objects(DAOs): 数据访问功能, 可以对数据库进行增删改查等操作。
2.MyBatis框架快速入门
2.1 MyBatis查询数据库操作
MyBatis的基本使用步骤如下:
-
1.在数据库中新建student表
-
2.在Maven中加入mybatis和mysql的相关依赖
-
3.创建实体类:student,用于保存数据库中student表中对应的一行数据。一般实体类在实现代码中都放在entity包中。
-
4.创建持久层的dao接口,定义操作数据库的方法(只需要声明方法即可)
-
package com.sysu.dao; import com.sysu.entity.Student; import java.util.List; public interface StudentDao { public ListselectStudents(); }
-
-
5.创建一个mybatis使用的配置文件:sql映射文件(一个xml文件,文件内容如下),然后在映射文件中写sql语句,一般一个表对应一个sql映射文件。
-
xml文件应该创建在接口所在的目录中,同时最好保证文件名称和接口名字一致。
-
<?xml version="1.0" encoding="UTF-8" ?>
-
-
6.创建mybatis的主配置文件:主配置文件提供了数据库的连接信息和sql映射文件的位置信息,一般一个项目对应一个主配置文件。配置文件内容如下:
-
<?xml version="1.0" encoding="UTF-8" ?>
-
-
7.获取SqlSession对象,通过它的方法执行sql语句。
-
public class myapp { public static void main(String[] args) throws IOException { //1.定义mybatis主配置文件的名称,从类路径开始(target/classes),如果target/classes路径下没有mybatis.xml,则说明mvn compile命令执行不完善,可以手动将mybatis.xml文件复制一份到target/classes目录下。 //通常情况下都会把12345这五个步骤封装至utils中。 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.从SqlSessionFactory对象中获取SqlSession对象,可以根据openSession()传入的参数自定义是否自动提交事务,openSession(true)表示自动提交事务。 SqlSession sqlSession = factory.openSession(); //67本质是StudentDao接口中selectStudents()方法的实现,该部分代码在后期可以省略,因为根据MyBatis动态代理可以达到同样的效果。 //6.【自定义】指定要执行的sql语句标识 String sqlId = "com.bjpowernode.dao.StudentDao.selectStudents"; //7.【自定义】执行sql语句,得到执行结果 ListstudentList = sqlSession.selectList(sqlId); for(Student st : studentList) System.out.println(st); sqlSession.close(); //上述代码执行查询操作,当执行insert、update、delete等操作时候一定要主动提交事务,否则数据库中的数据不改变. //sqlSession.commit(); ------------------------------------------------------------------------------ //动态代理的实现方式如下: //StudentDao dao = sqlSession.getMapper(StudentDao.class); //List students = dao.selectStudents(); //for(Student student : students) System.out.println(student); } }
-
第七个步骤 “获取SqlSession对象,通过它的方法执行sql语句",该步骤有两种实现方式:
- 传统Dao开发模式:实现StudentDao接口中的方法,并使用这些方法对数据库进行操作。
- MyBatis动态代理模式(必须掌握):MyBatis动态代理可以让我们省去实现StudentDao接口中的方法这一步骤,它会直接定位到映射文件 mapper 中的相应 SQL 语句,对DB进行操作。底层是通过反射进行实现的。
//动态代理的实现方式如下:
获取SqlSession对象
SqlSession sqlSession = factory.openSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
List students = dao.selectStudents();
for(Student student : students) System.out.println(student);
2.2 MyBatis Insert操作(使用动态代理)
MyBatis初始化的时候比较麻烦,日后在和数据库打交道就比较简单了。
- 1.在dao接口中定义操作数据库的方法(只需要声明方法即可)
package com.sysu.dao;
import com.sysu.entity.Student;
import java.util.List;
public interface StudentDao {
public List selectStudents();
//定义insert插入方法,该方法只有一个参数Student,所以在sql映射文件中不需要写parameterType=”“参数
//如果方法中有多个参数需要使用@Param命名参数(见3.3.2)
public int insertStudent(Student student);
}
- 2.在sql映射文件中写sql语句。
<?xml version="1.0" encoding="UTF-8" ?>
insert into student values(#{id},#{name},#{email},#{age})
- 3.获取SqlSession对象,通过MyBatis动态代理实现对数据库的访问与操作。
package com.sysu;
import com.sysu.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 java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class myapp {
public static void main(String[] args) throws IOException {
//通常把下面4个步骤封装至utils包中,用于获取SqlSession对象
String config = "mybatis.xml";
InputStream in = Resources.getResourceAsStream(config);
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//获取SqlSession对象
SqlSession sqlSession = factory.openSession();
//创建需要插入的student对象
Student student = new Student();
student.setId(1003);
student.setName("王五");
student.setEmail("ddd@qq");
student.setAge(35);
//Mybatis动态代理
StudentDao dao = sqlSession.getMapper(StudentDao.class);
int ans = dao.insertStudent(student);
System.out.println(ans);
}
}
3.MyBatis框架Dao代理(※)
3.1 实现步骤
实现步骤见2.1和2.2。或者见下图
3.2 实现原理
动态代理。
有关动态代理的内容见链接:动态代理
3.3 MyBatis相关参数的理解
(1)parameterType
<?xml version="1.0" encoding="UTF-8" ?>
parameterType表示StudentDao接口中方法参数的数据类型。parameterType不是强制的,mybatis通过反射机制能够发现接口参数的数据类型。所以可以没有。一般我们也不写。
例如StudentDao接口中存在方法:public Student selectStudentById(Integer id),则 parameterType="int"
在sql映射文件中,可以通过#{“任意字符”}获取简单类型的一个参数的值。例如通过#{id}获取selectStudentById(Integer id)方法中传入的id值。
实现原理如下:首先需要知道MyBatis就是对JDBC的一个封装
(1) MyBatis创建Connection以及PreparedStatement对象
String sql = “select id,name,email,age from student where id = ?”
PreparedStatement pst = conn.preparedStatement(sql);
// 一个问好就相当于一个占位符,setInt传入第一个参数
pst.setInt(1,1001);
(2) 执行sql封装为Student对象。
Resultset rs = ps.executeouery();student student = null;
while(rs.next()){
//从数据库取表的一行数据,存到一个java对象属性中ltudent = new student();
student.setId(rs.getInt("id));
student.setName(rs.getstring( "name" ));
student.setEmail(rs.getstring( "email"));
student.setAge(rs.getInt("age"));
}
return sfudent;
当我们在sql映射文件中写sql语句时,底层的实现原理就如(1)(2)两个步骤,所以可以认为MyBatis就是对JDBC进行了封装。
(2)@Param命名参数
在sql映射文件中,有两种常用的方法可以获取多个参数的值。
-
@Param命名参数获取多个参数的值使用方法:在dao接口声明的方法中加入@Param(“自定义参数名称”),然后在sql映射文件使用#{“自定义参数名称”}。
例如dao接口存在selectMulitParam()方法:
步骤一:public ListselectMulitParam(@Param("myname") String name, @Param("myage") Integer age)
步骤二:对应sql映射文件为:
-
通过传递类型为Java对象的参数来获取多个参数的值(其实insert的sql语句就是采用这种方式)
使用方法:在dao接口声明的方法中加入Java对象,然后在sql映射文件使用#{“对象的属性名”}。
步骤一:public List selectMulitParam(Student)
步骤二:对应sql映射文件为:
3.4 #和$的区别
首先需要明白:在sql映射文件中无论是使用“#”还是“$",都能正常工作!!
#:占位符,告诉mybatis使用实际的参数值代替。并使用PrepareStatement对象执行sql语句,#{"自定义字符"}代替 sql 语句的“?”。
这样做更安全,更迅速,通常也是首选做法。
sql映射文件
转为 MyBatis 的执行是:
String sql=” select id,name,email,age from student where id = ?”;
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1,1005);
where id=? 就是 where id = #{studentId}
ps.setInt(1,1005) , 1005 会替换掉 #{studentId}
$:主要用于替换表名或者列名。具体实例如下:
1.dao接口文件中声明方法:
List selectUse$Order(@Param("colName") String colName);
2.sql映射文件写sql语句
3.MyBatis动态代理实现与数据库的交互
SqlSession sqlSession = MyBatisUtils.getSqlSesson();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
// 根据name这一列的属性值进行排序
List students = dao.selectUse$Order("name")
两者的区别如下:
1. #使用?在sql语句中做占位符, 使用PreparedStatement执行sql,效率高。能避免sql注入,更安全。
2. $不使用占位符,表示字符串的连接,使用Statement对象执行sql,效率低。有sql注入的风险,缺乏安全性。
3. $主要用于替换表名或者列名,一般在数据需要根据某个列属性进行排序的场景下使用。
3.5 MyBatis的输出结果
MyBatis的输出结果为Java对象,MyBatis通过使用resultType以及resultMap两种参数让MyBatis明白sql语句执行结果需要转换的对象类型。
(1) resultType
表示sql语句的执行结果需要转换的Java对象类型。
public Student selectStudentById(@Param("id") Integer id);
- resultType的值可以看成是dao接口中方法的返回类型。它的值有两种:1. 类型的全限定名称(推荐)。 2. 类型的别名, 例如 java.lang.Integer别名是int
- 实现原理:把同名列的值赋给resultType中指定对象的同名属性,例如:查询结果id列的值赋给Student中的id属性,name列的值赋给Student中的name属性。这一过程是通过对象的get、set方法实现的,因此对象中一定要实现get、set方法。
public List selectStudents();
这种情况下resultType不能等于List,因为列值id,name,email,age这些是Student对象的属性,而不是List对象的属性。
(2) resultMap
MyStudent类的定义
class MyStudent{
Integer Myid;
String Myname;
String Myemail;
Integer Myage;
}
dao接口中定义的方法:public List selectStudents();
sql映射文件:
当列名(id,name,email,age)和对象中的属性名(Myid、Myname、Myemail、Myage)不一样时,使用resultType将会得到null的对象,解决方案:
- 使用别名
修改sql映射文件
- 使用resultMap
resultMap可以自定义sql执行结果的列名和 对象中的属性名之间映射关系。常用在列名和 java 对象属性名不一样的情况。
使用方式:
1.在sql映射文件中定义resultMap,指定列名和属性的对应关系。
2.在中把 resultType 替换为 resultMap。
3.6 like模糊查询
MyBatis有两种方式实现like模糊查询
- 1. java代码中给查询数据加上“%” (最常用)
接口方法:
List selectLikeFirst(String name);
sql映射文件(mapper文件):
测试方法:
@Test
public void testSelectLikeOne(){
String name="%李%";
List stuList = studentDao.selectLikeFirst(name);
for(Student stu : stuList) ystem.out.println(stu);
}
- 2.在mapper文件sql语句的条件位置加上“%”
接口方法:
List selectLikeSecond(String name);
mapper 文件:
测试方法:
@Test
public void testSelectLikeSecond(){
String name="李";
List stuList = studentDao.selectLikeSecond(name);
for(Student stu : stuList) ystem.out.println(stu);
}
4.MyBatis框架动态SQL(※)
动态sql: sql的内容是变化的,可以根据条件获取到不同的sql语句。主要是where部分发生变化。MyBatis主要通过这三个常用标签实现动态sql:、、
4.1 if 标签
标签用于条件判断,当条件判断为true时,会将其包含的sql片段拼接到其所在的sql语句中。
部分sql语句
1.dao接口声明的方法如下:
public List selectStudentIf(Student student);
2.sql映射文件内容如下:
3.test测试
@Test
public void testSelectStudentIf(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
Student dao = sqlSession.getMapper(StudentDao.class);
Student student = new Student();
student.setName("abc");
student.setAge(18);
List students = dao.selectStudentIf(student);
for(Student stu:students) System.out.println(stu);
}
此代码段的含义为:在数据中查找所有名字为“abc”或者年龄大于18的数据。
4.2 where标签
标签的中存在一个比较麻烦的地方:需要在 where 后手工添加 1=1 的子句。因为,若where后的所有条件均为 false,而 where 后若又没有 1 = 1 子句,则 SQL 中就会只剩下一个空的 where,SQL出错。所以,在where后,需要添加永为真子句1 = 1,以防止这种情况的发生。但当数据量很大时,会 严重影响查询效率。- 通过使用
标签可以避免产生此类问题,标签通常用来包含多个标签,当多个标签中有一个成立的,会自动增加一个where关键字,并去掉标签中sql语句多余的and ,or等。当没有标签成立,则不会添加where子句。
dao接口声明的方法:
List selectStudentWhere(Student student);
sql映射文件
测试方法:
@Test
public void testSelectWhere() throws IOException {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
Student dao = sqlSession.getMapper(StudentDao.class);
Student param = new Student();
param.setName("abc");
param.setAge(18);
List studentList = studentDao.selectStudentWhere(param);
for(Student stu:students) System.out.println(stu);
}
此代码段的含义为:在student表中查找所有名字为“abc”或者年龄大于18的数据。如果两个条件都不满足,则输出student表中的全部数据。
4.3 foreach标签
标签用于实现对于数组与集合的遍历,一般用于dao接口文件中声明的方法的传入参数为数组或者集合。- 主要用在sql的in语句中。
select * from student where id in (1001,1002,1003)
使用语法:
#{item的值}
collection:表示接口中的方法参数的类型,如果是数组使用array, 如果是list集合使用list,集合的大小用 list.size()表示。
item:自定义的,表示数组和集合成员的变量
open:循环开始的字符
close:循环结束的字符
separator:集合成员之间的分隔符
因为foreach一般用于sql中的in语句,所以open="(" close=")" separator=","
遍历List<简单类型>
需求:输出学生id为1002,1005,1006的学生信息。
接口方法:
List selectStudentForList(List idList);
sql映射文件
测试方法:
@Test
public void testSelectForList() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
Student dao = sqlSession.getMapper(StudentDao.class);
List list = new ArrayList<>();
list.add(1002);
list.add(1005);
list.add(1006);
List studentList = studentDao.selectStudentForList(list);
for(Student stu:students) System.out.println(stu);
}
遍历List<对象类型>
需求:输出学生id为1002,1005的学生信息。
接口方法:
List selectStudentForList(List idList);
sql映射文件
测试方法:
@Test
public void testSelectForList() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
Student dao = sqlSession.getMapper(StudentDao.class);
List list = new ArrayList<>();
Student s1 = new Student();
s1.setId(1002)
list.add(s1);
s1 = new Student();
s1.setId(1005);
list.add(s1);
List studentList = studentDao.selectStudentForList(list);
for(Student stu:students) System.out.println(stu);
}
4.4 sql标签
标签用于定义 SQL 片断,以便其它SQL标签可以复用定义好的片段。- 其它标签使用该 SQL 片断,需要使用
标签。 标签可以定义 SQL 语句中的任何部分,所以子标签可以放在动态 SQL 的任何位置。
先定义: 可以是sql语句、表名、字段名等
再使用:
接口方法:
List selectStudentSqlFragment(List stuList);
sql映射文件:
select id,name,email,age from student
测试方法:
@Test
public void testSelectForList() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
Student dao = sqlSession.getMapper(StudentDao.class);
List list = new ArrayList<>();
Student s1 = new Student();
s1.setId(1002)
list.add(s1);
s1 = new Student();
s1.setId(1005);
list.add(s1);
List studentList = studentDao.selectStudentForList(list);
for(Student stu:students) System.out.println(stu);
}
借助sql标签输出学生id为1002,1005的学生信息。
5.MyBatis配置文件(了解)
MyBatis有两种配置文件:主配置文件以及sql映射文件(mapper文件)
5.1 主配置文件
<?xml version="1.0" encoding="UTF-8" ?>
主配置文件一般放在resourcs目录下,且命名为xxx.xml。主配置文件的具体内容可以见2.1
主配置文件特点:
-
主配置文件中
之间的标签都是有序的,且为根标签-
:指定属性配置文件的位置 -
:配置别名 -
:配置插件 -
:定义数据源 -
:定义sql映射文件的位置
-
-
xml 文件,需要在头部使用约束文件
<?xml version="1.0" encoding="UTF-8" ?>
属性配置文件的书写
数据库的属性配置文件: 把数据库连接信息放到一个单独的文件中。 和mybatis主配置文件分开。目的是便于修改,保存,处理多个数据库的信息。
(1) 在resources目录中定义一个属性配置文件,xxxx.properties,例如 jdbc.properties。在属性配置文件中进行数据的定义,格式是key = value。
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql//.....
jdbc.username=root
jdbc.password=123456
(2) 在mybatis的主配置文件中,使用指定属性配置文件的位置,然后在需要使用的地方利用${key}进行值的引入。
5.2 sql映射文件
详细内容见2.1即可。