中文文档
https://mybatis.org/mybatis-3/zh/index.html
1、简介
什么是MyBatis
MyBatis
是一个优秀的基于java
的持久层框架,内部封装了jdbc
,开发者只需要关注 sql 语句 本身,而不需要处理加载驱动、创建连接、创建statement
、关闭连接,资源等繁杂的过程。MyBatis
通过 xml 或注解两种方式将要执行的各种sql
语句配置起来,并通过java
对象和sql
的动态参数进行映射生成最终执行的sql
语句,最后由mybatis框架执行sql
并将结果映射为java
对象并返回。MyBatis
本是apache
的一个开源项目iBatis
, 2010 年这个项目由apache software foundation
迁 移到了google code
,并且改名为MyBatis
。2013 年 11 月迁移到Github
。iBATIS
一词来源于“internet
”和“abatis
”的组合,是一个基于Java
的持久层框架。iBATIS
提供的 持久层框架包括SQL Maps
和Data Access Objects(DAOs)
MyBatis解决的主要问题
减轻使用 JDBC 的复杂性,不用编写重复的创建 Connetion , Statement ; 不用编写关闭资源代码。 直接使用 java 对象,表示结果数据。让开发者专注 SQL 的处理。 其他分心的工作由 MyBatis 代劳。
-
MyBatis可以完成
- 注册数据库的驱动,例如 Class.forName(“com.mysql.jdbc.Driver”))
- 创建 JDBC 中必须使用的 Connection , Statement, ResultSet 对象
- 从 xml 中获取 sql,并执行 sql 语句,把 ResultSet 结果转换 java 对象
List<Student> list = new ArrayLsit<>(); ResultSet rs = state.executeQuery(“select * from student”); while(rs.next){ Student student = new Student(); student.setName(rs.getString(“name”)); student.setAge(rs.getInt(“age”)); list.add(student); }
- 关闭资源
ResultSet.close() , Statement.close() , Conenection.close()
2、入门案例(CRUD)
基本步骤
创建数据库表
新建测试类和实体类
package com.phz.entity;
/**
* @author PengHuAnZhi
* @createTime 2020/11/10 8:53
* @projectName MyBatis
* @className Student.java
* @description TODO
*/
public class Student {
private String id;
private String name;
private Integer age;
private String email;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "Student{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age='" + age + '\'' +
", email='" + email + '\'' +
'}';
}
}
修改pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>MyBatisDemo</artifactId>
<version>1.0-SNAPSHOT</version>
<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.4.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</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>
</project>
特别注意目录名必须对应
编写Dao接口
package com.phz.dao;
import com.phz.entity.Student;
/**
* @author PengHuAnZhi
* @createTime 2020/11/10 11:07
* @projectName MyBatis
* @className StudentDao.java
* @description TODO
*/
public interface StudentDao {
/*查询所有学生*/
Student selectStudent(String id);
int insertStudent(Student student);
int deleteStudent(int id);
int updateStudent(String id,String name,Integer age,String email);
}
编写Dao接口Mapper映射文件StudentDao.xml
IDEA
是不会编译src
的java
目录的xml
文件,所以在MyBatis
的配置文件中找不到xml
文件!(也有可能是Maven
构建项目的问题,网上教程很多项目是普通的Java web
项目,所以可以放到src
下面也能读取到)
<?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">
<!--
namespace:必须有值,自定义的唯一字符串
推荐使用:dao 接口的全限定名称
-->
<mapper namespace="com.phz.dao.StudentDao">
<!--
<select>: 查询数据, 标签中必须是 select 语句
id: sql 语句的自定义名称,推荐使用 dao 接口中方法名称,
使用名称表示要执行的 sql 语句
resultType: 查询语句的返回结果数据类型,使用全限定类名
-->
<select id="selectStudents" resultType="com.phz.entity.Student">
<!--要执行的 sql 语句-->
select id,name,email,age from student where id = #{id}
</select>
<insert id="insertStudent">
insert into student(id,name,email,age)
values (#{id},#{name},#{email},#{age})
</insert>
<delete id="deleteStudent">
delete from student where id=#{id}
</delete>
<update id="updateStudent">
update student set name = #{name},age = #{age},email = #{email} where id=#{id}
</update>
</mapper>
创建MyBatis主配置文件
项目
src/main
下创建resources
目录,设置resources
目录为resources root
创建主配置文件:名称为mybatis-config.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>
<!--settings:控制mybatis全局行为-->
<settings>
<!--设置mybatis输出日志-->
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
<!--配置 mybatis 环境-->
<environments default="mysql">
<!--id:数据源的名称-->
<environment id="mysql">
<!--配置事务类型:使用 JDBC 事务(使用 Connection 的提交和回滚)-->
<transactionManager type="JDBC"/>
<!--数据源 dataSource:创建数据库 Connection 对象
type: POOLED 使用数据库的连接池,MyBatis会创建一个数据库连接池,连接池的一个连接将会被用作数据库操作。一旦数据库操作完成,MyBatis会将此连接返回给连接池。在开发或测试环境中经常用到此方式
UNPOOLED MyBatis会为每一个数据库操作创建一个新的连接,并关闭它。该方式适用于只有小规模数量并发用户的简单应用程序上
JNDI MyBatis会从在应用服务器向配置好的JNDI数据源DataSource获取数据库连接。在生产环境中优先考虑这种方式。
-->
<dataSource type="POOLED">
<!--连接数据库的四个要素-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis_test?useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--告诉 mybatis 要执行的 sql 语句的位置-->
<mapper resource="StudentDao.xml"/>
</mappers>
</configuration>
测试
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;
/**
* @author PengHuAnZhi
* @createTime 2020/11/9 11:23
* @projectName MyBatis
* @className Test.java
* @description TODO
*/
public class MyTest {
@Test
public void testSelect() throws IOException {
//1、mybatis主配置文件
String config = "mybatis-config.xml";
//2、读取配置文件
InputStream inputStream = Resources.getResourceAsStream(config);
//3、创建SqlSessionFactory对象,目的是获取SqlSession
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//4、读取SqlSession,SqlSession能执行sql语句
SqlSession sqlSession = sqlSessionFactory.openSession();
//5、执行SqlSession的selectList()
Student student = sqlSession.selectOne("com.phz.dao.StudentDao.selectStudents", "2018011875");
//6、循环输出查询结果
System.out.println(student.toString());
//7、关闭SqlSession,释放资源
sqlSession.close();
}
@Test
public void testInsert() throws IOException {
//1、mybatis主配置文件
String config = "mybatis-config.xml";
//2、读取配置文件
InputStream inputStream = Resources.getResourceAsStream(config);
//3、创建SqlSessionFactory对象,目的是获取SqlSession
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//4、读取SqlSession,SqlSession能执行sql语句
SqlSession sqlSession = sqlSessionFactory.openSession();
Student student = new Student();
student.setId("2018011320");
student.setName("319宿舍");
student.setAge(2);
student.setEmail("[email protected]");
int result = sqlSession.insert("com.phz.dao.StudentDao.insertStudent", student);
//mybatis默认不是自动提交事务的, 所以在insert ,update ,delete后要手工提交事务
sqlSession.commit();
System.out.println(result);
sqlSession.close();
}
@Test
public void testDelete() throws IOException {
//1、mybatis猪配置文件
String config = "mybatis-config.xml";
//2、读取配置文件
InputStream inputStream = Resources.getResourceAsStream(config);
//3、创建SqlSessionFactory对象,目的是获取SqlSession
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//4、读取SqlSession,SqlSession能执行sql语句
SqlSession sqlSession = sqlSessionFactory.openSession();
//5、执行sql语句
int result = sqlSession.delete("com.phz.dao.StudentDao.deleteStudent", "2018011320");
sqlSession.commit();
System.out.println(result);
sqlSession.close();
}
@Test
public void testUpdate() throws IOException {
String config = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(config);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
String id = "2018011875";
Student student = sqlSession.selectOne("com.phz.dao.StudentDao.selectStudents", id);
if (student != null) {
student.setAge(30);
int result = sqlSession.update("com.phz.dao.StudentDao.updateStudent",student);
System.out.println(result);
}
//不写提交默认回滚,起不到更新的目的
sqlSession.commit();
sqlSession.close();
}
}
相关API
Resources
Resources
类,顾名思义就是资源,用于读取资源文件。其有很多方法通过加载并解析资源文件,返回不同类型的IO
流对象。
SqlSessionFactory
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
在方法内部创建,使用完毕后关闭。
使用MyBatisUtil对象
package com.phz.util;
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.InputStream;
/**
* @author PengHuAnZhi
* @createTime 2020/11/10 21:57
* @projectName MyBatis
* @className MybatisUtil.java
* @description TODO
*/
public class MybatisUtil {
private static SqlSessionFactory sqlSessionFactory = null;
static {
try{
String config = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(config);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}catch (Exception e){
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
SqlSession sqlSession = null;
if(sqlSessionFactory != null){
//创建一个默认提交事务的SqlSession
sqlSession = sqlSessionFactory.openSession(true);
}
return sqlSession;
}
}
@Test
public void testSelect() throws IOException {
SqlSession sqlSession = MybatisUtil.getSqlSession();
//5、执行SqlSession的selectList()
Student student = sqlSession.selectOne("com.phz.dao.StudentDao.selectStudents", "2018011875");
//6、循环输出查询结果
//studentList.forEach(student -> System.out.println(student));
System.out.println(student.toString());
//7、关闭SqlSession,释放资源
sqlSession.close();
}
Dao开发
就是编写一个
StudentDao
接口的实现类,并实现里面写的数据操作方法,需要的时候直接调用就可以,下面仅实现一个查询方法,其他同理
package com.phz.Service;
import com.phz.dao.StudentDao;
import com.phz.entity.Student;
import com.phz.util.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
/**
* @author PengHuAnZhi
* @createTime 2020/11/10 22:05
* @projectName MyBatis
* @className StudentDaoImpl.java
* @description TODO
*/
public class StudentDaoImpl implements StudentDao {
private static StudentDaoImpl studentDao;
static {
if (studentDao == null) {
studentDao = new StudentDaoImpl();
}
}
public static StudentDaoImpl getInstance() {
return studentDao;
}
@Override
public Student selectStudent(String id) {
SqlSession sqlSession = MybatisUtil.getSqlSession();
Student student = sqlSession.selectOne("com.phz.dao.StudentDao.selectStudents", "2018011875");
sqlSession.close();
return student;
}
@Override
public int insertStudent(Student student) {
return 0;
}
@Override
public int deleteStudent(int id) {
return 0;
}
@Override
public int updateStudent(String id, String name, Integer age, String email) {
return 0;
}
}
测试
@Test
public void testSelect() throws IOException {
System.out.println(StudentDaoImpl.getInstance().selectStudent("2018011875").toString());
}
思考:
Dao
的实现类其实并没有干什么实质性的工作,它仅仅就是通过SqlSession
的相关API
定位到映射文件mapper
中相应id
的SQL
语句,真正对DB
进行操作的工作其实是由框架通过mapper
中的SQL
完成的。
- 所以,
MyBatis
框架就抛开了Dao
的实现类,直接定位到映射文件mapper
中的相应SQL
语句,对DB
进行操作。这种对Dao
的实现方式称为Mapper
的动态代理方式。Mapper
动态代理方式无需程序员实现Dao
接口。接口是由MyBatis
结合映射文件自动生成的动态代 理实现的。
3、Mybatis框架Dao代理
代码改造
Dao代理实现CRUD,不需要手动编写接口的实现类对象,直接调用SqlSession的getMapper方法,即可获取指定接口的实现类对象。
使用Dao代理修改插入方法:
@Test
public void testInsert() throws IOException {
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = new Student();
student.setId("2018011320");
student.setName("319宿舍");
student.setAge(2);
student.setEmail("[email protected]");
int result = studentDao.insertStudent(student);
//mybatis默认不是自动提交事务的, 所以在insert ,update ,delete后要手工提交事务
sqlSession.commit();
System.out.println(result);
sqlSession.close();
}
分析原理:
查看MapperProxy源码
查看execute方法源码:
深入解析Mapper映射文件
parameterType
<select id="selectStudents" resultType="com.phz.entity.Student" parameterType="String">
<!--要执行的 sql 语句-->
select id,name,email,age from student where id = #{
id}
</select>
这个属性是可选的,因为
MyBatis
可以推断出具体传入语句的参数,默认值为未设置(unset)
。接口中方法的参数从java
代码传入到mapper
文件的sql
语句。
其中的参数写法不唯一:
int
或java.lang.Integer
hashmap
或java.util.HashMap
list
或java.util.ArrayList
student
或com.phz.entity.Student
select
,insert
,update
,delete
都可以使用parameterType
指定类型
传递参数
一个简单参数
Dao
接口中方法的参数只有一个简单类型(java
基本类型和 String
),占位符 #
{ 任意字符 },和方法的参数名无关,如:
Student selectStudent(String studentId);//StudentDao中定义的查询方法
<select id="selectStudents" resultType="com.phz.entity.Student" parameterType="String">
<!--要执行的 sql 语句-->
select id,name,email,age from student where id = #{id}
</select>
#{id}
,id
是自定义的变量名称,和方法参数名无关。
多个参数-@Param
如果是多个参数,就必须通过名称使用该参数,在方法形参前面加入@Param("自定义参数名")
Student selectStudentMultiParam(@Param("studentId") String id , @Param("studentName") String name);
<select id="selectStudentMultiParam" resultType="com.phz.entity.Student">
select * from student where id = #{studentId} and name = #{studentName}
</select>
@Test
public void testSelect() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = studentDao.selectStudentMultiParam("2018011875","彭焕智");
System.out.println(student.toString());
}
多个参数-对象
<select id="selectStudentObject" resultType="com.phz.entity.Student">
select * from student where id = #{queryId} and name = #{queryName}
</select>
<select id="selectStudentObject" resultType="com.phz.entity.Student">
select * from student where id = #{queryId,javaType=String,jdbcType=VARCHAR} and name = #{queryName,javaType=String,jdbcType=VARCHAR}
</select>
@Test
public void testSelect() {
QueryParam queryParam = new QueryParam();
queryParam.setQueryId("2018011875");
queryParam.setQueryName("彭焕智");
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = studentDao.selectStudentObject(queryParam);
System.out.println(student.toString());
}
多个参数-按位置
<select id="selectStudentLocation" resultType="com.phz.entity.Student">
select * from student where id = #{arg0} and name = #{arg1}
</select>
Student selectStudentLocation(String id,String name);
@Test
public void testSelect() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = studentDao.selectStudentLocation("2018011875","彭焕智");
System.out.println(student.toString());
}
多个参数-Map
<select id="selectStudentMap" resultType="com.phz.entity.Student">
select * from student where id = #{myId} and name = #{myName}
</select>
Student selectStudentMap(Map<String,Object> map);
@Test
public void testSelect() {
Map<String ,Object> map = new HashMap<>();
map.put("myId","2018011875");
map.put("myName","彭焕智");
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = studentDao.selectStudentMap(map);
System.out.println(student.toString());
}
#和$
- #:占位符,告诉
mybatis
使用实际的参数值代替。并使用PrepareStatement
对象执行sql
语句,#{…}
代替 sql 语句的“?”
。这样做更安全,更迅速,通常也是首选做法。
<select id="selectStudentById" resultType="com.phz.entity.Student">
select * from student where id = #{studentId}
</select>
<select id="selectStudentByEmail" resultType="com.phz.entity.Student">
select * from student where email = #{studentEmail}
</select>
Student selectStudentById(String id);
Student selectStudentByEmail(String email);
@Test
public void testSelect() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
System.out.println(studentDao.selectStudentById("2018011875").toString());
System.out.println(studentDao.selectStudentByEmail("[email protected]").toString());
}
转换为mybatis执行的就是
String sql=” select id,name,email,age from student where id=?”;
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1,"2018011875");
- == 字 符 串 替 换 = = , 告 诉 ‘ m y b a t i s ‘ 使 用 ‘ 字符串替换==,告诉 `mybatis` 使用` 字符串替换==,告诉‘mybatis‘使用‘
包含的“字符串”替换所在位置。使用
Statement把
sql语句和
${}`的 内容连接起来。主要用在替换表名,列名,不同列排序等操作.
//使用不同列作为查询条件
Student selectStudentByDiffField(@Param("col") String colunName,@Param("cval") Object value);
<select id="selectStudentByDiffField" resultType="com.phz.entity.Student">
select * from student where ${col} = #{cval}
</select>
@Test
public void testSelect() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
//按照email列查询
System.out.println(studentDao.selectStudentByDiffField("email","[email protected]"));
}
封装Mybatis输出结果
resultType
- 简单类型(
int
等) - 对象类型(
Student
等) - 如果返回的参数是一个集合,那么需要指定的是集合中的类型,而不是集合本身
<select id="selectAll" resultType="com.phz.entity.Student">
select * from student;
</select>
List<Student> selectAll();
@Test
public void testSelect() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
//lambda表达式
studentDao.selectAll().forEach((e) -> System.out.println(e));
studentDao.selectAll().forEach(System.out::println);
}
map
:sql
的查询结果作为Map
的key
和value
。
注意:Map
作为接口返回值,sql
语句的查询结果最多只能有一条记录。大于一条记录是错误。
<select id="selectReturnMap" resultType="java.util.Map">
select * from student where id = #{studentId}
</select>
Map<Object, Object> selectReturnMap(String id);
@Test
public void testSelect() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
System.out.println(studentDao.selectReturnMap("2018011875"));
}
这里查询结果前者是键,如
id
,后者是值,如2018011875
。
resultMap
:可以自定义sql
的结果和java
对象属性的映射关系。更灵活的把列值赋值给指定属性。 常用在列名和java
对象属性名不一样的情况。
<!-- 创建 resultMap
id:自定义的唯一名称,在<select>使用
type:期望转为的 java 对象的全限定名称或别名
-->
<resultMap id="studentMap" type="com.phz.entity.Student">
<!-- 主键字段使用 id -->
<id column="id" property="id"/>
<!--非主键字段使用 result-->
<result column="name" property="name"/>
<result column="email" property="email"/>
<result column="age" property="age"/>
</resultMap>
<!--resultMap: resultMap 标签中的 id 属性值-->
<select id="selectUseResultMap" resultMap="studentMap">
select * from student where id = #{queryId} or name = #{queryName}
</select>
List<Student> selectUseResultMap(QueryParam queryParam);
@Test
public void testSelect() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
QueryParam queryParam = new QueryParam();
queryParam.setQueryId("2018011875");
queryParam.setQueryName("彭焕智");
studentDao.selectUseResultMap(queryParam).forEach((e) -> System.out.println(e));
}
实体类属性名和列名不同的处理方式
使用列别名和resultType
创建一个新的实体测试类
package com.phz.entity;
/**
* @author PengHuAnZhi
* @createTime 2020/11/11 22:31
* @projectName MyBatis
* @className PrimaryStudent.java
* @description TODO
*/
public class PrimaryStudent {
private String stuId;
private String stuName;
private Integer stuAge;
public String getStuId() {
return stuId;
}
public void setStuId(String stuId) {
this.stuId = stuId;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public Integer getStuAge() {
return stuAge;
}
public void setStuAge(Integer
stuAge) {
this.stuAge = stuAge;
}
@Override
public String toString() {
return "PrimaryStudent{" +
"stuId='" + stuId + '\'' +
", stuName='" + stuName + '\'' +
", stuAge='" + stuAge + '\'' +
'}';
}
}
List<PrimaryStudent> selectUseFieldAlias(QueryParam queryParam);
<select id="selectUseFieldAlias" resultType="com.phz.entity.PrimaryStudent">
select id as stuId,name as stuName,age as stuAge from student where id=#{queryId} and name=#{queryName}
</select>
public void testSelect() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
QueryParam queryParam = new QueryParam();
queryParam.setQueryId("2018011875");
queryParam.setQueryName("彭焕智");
studentDao.selectUseFieldAlias(queryParam).forEach(System.out::println);
}
使用resultMap
<!-- 创建 resultMap
id:自定义的唯一名称,在<select>使用
type:期望转为的 java 对象的全限定名称或别名
-->
<resultMap id="primaryStudentMap"
type="com.phz.entity.PrimaryStudent">
<!-- 主键字段使用 id -->
<id column="id" property="stuId"/>
<!--非主键字段使用 result-->
<result column="name" property="stuName"/>
<result column="age" property="stuAge"/>
</resultMap>
<!--resultMap: resultMap 标签中的 id 属性值-->
<select id="selectUseDiffResultMap" resultMap="primaryStudentMap">
select * from student where id=#{queryId} or name=#{queryName}
</select>
List<PrimaryStudent> selectUseDiffResultMap(QueryParam param);
@Test
public void testSelect() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
QueryParam param = new QueryParam();
param.setQueryId("2018011875");
param.setQueryName("彭焕智");
List<PrimaryStudent> stuList;
stuList = studentDao.selectUseDiffResultMap(param);
stuList.forEach( stu -> System.out.println(stu));
}
模糊like
java
代码中提供要查询的 “%2018011875%
”
<select id="selectLikeFirst" resultType="com.phz.entity.Student">
select * from student where id like #{studentId}
</select>
List<Student> selectLikeFirst(String name);
@Test
public void testSelect() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Student> studentList = studentDao.selectLikeFirst("%2018011875%");
studentList.forEach(System.out::println);
}
mapper
文件中使用like name "%" #{xxx} "%"
List<Student> selectLikeSecond(String id);
<select id="selectLikeSecond" resultType="com.phz.entity.Student">
select * from student where id like "%" #{studentId} "%"
</select>
@Test
public void testSelect() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Student> studentList = studentDao.selectLikeSecond("2018011875");
studentList.forEach(System.out::println);
}
MyBatis框架动态SQL
特别注意,在xml
中出现大于小于等符号,可能会导致解析出现问题,必须使用对应的实体符号代替!
数学符号 | 语义 | 实体符号 |
---|---|---|
< | 小于 | ⁢ |
> | 大于 | > |
>= | 大于等于 | >= |
<= | 小于等于 | ⁢= |
<if>
<select id="selectStudentIf" resultType="com.phz.entity.Student">
<!--要执行的 sql 语句-->
select * from student where 1=1
<if test="name != null and name != ''">
<!--第一个if中的and可以不写,写上也不会错,系统会将多余的一个and删除,但是剩下的都必须写上-->
and name = #{name}
</if>
<if test="age > 0">
and age > #{age}
</if>
</select>
Student selectStudentIf(Student student);
@Test
public void testIf(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = new Student();
student.setName("彭焕智");
student.setAge(20);
System.out.println(studentDao.selectStudentIf(student).toString());
}
标签的中存在一个比较麻烦的地方:需要在
where
后手工添加 1=1 的子句,不然如果出现后面的if
语句全部为false
的时候,sql
语句就会出错,但是当数据量很大的时候,这样的效率就会很低
<where>
<select id="selectStudentWhere" resultType="com.phz.entity.Student">
select * from student
<where>
<if test="name != null and name != ''">
and name = #{name}
</if>
<if test="age > 0">
and age > #{age}
</if>
</where>
</select>
Student selectStudentWhere(Student student);
@Test
public void testWhere(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = new Student();
student.setName("彭焕智");
student.setAge(20);
System.out.println(studentDao.selectStudentWhere(student));
}
<foreach>
List<简单类型>
collection
表示要遍历的集合类型,list
,array
等。
open
、close
、separator
为对遍历内容的SQL
拼接。
<select id="selectStudentForList" resultType="com.phz.entity.Student">
select * from student
<if test="list != null and list.size > 0">
where id in
<foreach collection="list" open="(" close=")" item="id" separator=",">
#{id}
</foreach>
</if>
</select>
List<Student> selectStudentForList(List<String> list);
@Test
public void testList(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<String> list = new ArrayList<>();
list.add("2018011875");
list.add("2018011874");
list.add("2018011876");
List<Student> studentList = studentDao.selectStudentForList(list);
studentList.forEach(System.out::println);
}
List<对象>
<select id="selectStudentForObjectList" resultType="com.phz.entity.Student">
select * from student
<if test="list != null and list.size >0">
where id in
<foreach collection="list" open="(" close=")" separator="," item="student">
#{student.id}
</foreach>
</if>
</select>
List<Student> selectStudentForObjectList(List<Student> studentList);
@Test
public void testObjectList() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Student> studentList = new ArrayList<>();
Student student = new Student();
student.setId("2018011875");
studentList.add(student);
student = new Student();
student.setId("2018011874");
studentList.add(student);
student = new Student();
student.setId("2018011876");
studentList.add(student);
studentDao.selectStudentForObjectList(studentList).forEach(System.out::println);
}
代码片段
标签用于定义
SQL
片断,以便其它SQL
标签复用。而其它标签使用该SQL
片断,需要使用 子标签。该标签可以定义SQL
语句中的任何部分,所以子标签可以放在动态SQL
的任何位置。
<sql id="studentSql">
select *
from student
</sql>
<select id="selectStudentForSqlFragment" resultType="com.phz.entity.Student">
<include refid="studentSql"/>
<if test="list != null and list.size >0">
where id in
<foreach collection="list" open="(" close=")" separator="," item="student">
#{student.id}
</foreach>
</if>
</select>
List<Student> selectStudentForSqlFragment(List<Student> studentList);
@Test
public void testSqlfragment() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Student> studentList = new ArrayList<>();
Student student = new Student();
student.setId("2018011875");
studentList.add(student);
student = new Student();
student.setId("2018011874");
studentList.add(student);
student = new Student();
student.setId("2018011876");
studentList.add(student);
studentDao.selectStudentForSqlFragment(studentList).forEach(System.out::println);
}
MyBatis配置文件
一般情况,数据库的连接四要素都是存放在一个专门的配置文件中,然后MyBatis主配置文件再去读取他。
MyBatis支持别名
需要在主配置文件中声明
<typeAliases>
<!--
定义单个类型的别名
tyoe:类型的全限定名称
alias:自定义别名
-->
<typeAlias type="com.phz.entity.Student" alias="student"/>
<!--
批量定义别名,扫描整个包下的类,别名为类名(首字母大小写都可以)
name:包名
-->
<package name="com.phz.entity"/>
</typeAliases>
小扩展
- 基于PageHelper的分页
第一步:引入maven坐标
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
第二步:在主配置文件中的environments节点前加入plugin配置
<plugins>
<!-- com.github.pagehelper为PageHelper类所在包名 -->
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- 使用下面的方式配置参数,后面会有所有的参数介绍 -->
<property name="helperDialect" value="mysql"/>
</plugin>
</plugins>
第三步:使用
@Test
public void testPageHelper(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
PageHelper.startPage(1,3);
List<Student> studentList = new ArrayList<>();
Student student = new Student();
student.setId("2018011875");
studentList.add(student);
student = new Student();
student.setId("2018011874");
studentList.add(student);
student = new Student();
student.setId("2018011876");
studentList.add(student);
studentDao.selectStudentForSqlFragment(studentList).forEach(System.out::println);
}
将PageHelper.startPage(1,3);改为PageHelper.startPage(1,1);