mybatis01
Lombok
一、Lombok的使用
- Lombok 是一个Java库,能自动插入编辑器并构建工具,简化Java开发。
- 通过加注解的方式,不需要为类编写getter、setter、constructor或equals,同时可以自动化日志变量。
第一步、在pom.xml中加载Lombok的jar包
<?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>com.etime</groupId>
<artifactId>day0414</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<spring.version>5.2.5.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
</dependencies>
</project>
第二步、安装Lombok
第三步、Lombok使用
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Student {
private String id;
private String name;
private String gender;
private Date birthday;
private String s_class;
private String photo;
}
第四步、Lombok测试
import com.etime.pojo.Student;
public class StudentTest {
public static void main(String[] args) {
Student s1 = new Student();
s1.setId("1");
s1.setName("mary");
System.out.println(s1);
Student s2 = new Student("2","tom","男",null,"101",null);
System.out.println(s2);
}
}
// 结果
Student(id=1, name=mary, gender=null, birthday=null, s_class=null, photo=null)
Student(id=2, name=tom, gender=男, birthday=null, s_class=101, photo=null)
Process finished with exit code 0
二、Lombok常用注解
- @Setter
- 位置:注解在类或字段
- 使用:
- 注解在类:为所有字段生成setter方法
- 注解在字段:只为该字段生成setter方法
- @Getter
- 位置:注解在类或字段
- 使用:
- 注解在类:为所有字段生成getter方法g
- 注解在字段:只为该字段生成getter方法
- @ToString
- 位置:注解在类
- 使用:
- 注解在类:添加toString方法
- @EqualsAndHashCode
- 位置:注解在类
- 使用:
- 注解在类:生成hashCode和equals方法。
- @NoArgsConstructor
- 位置:注解在类
- 使用:
- 注解在类:生成无参的构造方法。
- @RequiredArgsConstructor
- 位置:注解在类
- 使用:
- 注解在类:为类中需要特殊处理的字段生成构造方法,比如final和被@NonNull注解的字段。
- @AllArgsConstructor
- 位置:注解在类
- 使用:
- 注解在类:生成包含类中所有字段的构造方法。
- @AllArgsConstructor
- 位置:注解在类
- 使用:
- 注解在类:生成setter/getter、equals、canEqual、hashCode、toString方法,若为final属性,则不会为该属性生成setter方法。
Mybatis
一、Mybatis简介
二、Mybatis的基本使用方式
1、创建maven工程,引入依赖
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</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.47</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
2、编写实体类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Student {
private String id;
private String name;
private String gender;
private Date birthday;
private String s_class;
private String photo;
}
3、编写dao层接口
import com.etime.pojo.Student;
import java.util.List;
public interface StudentDao {
// 查询所有学生信息
List<Student> getAllStudents();
}
4、编写dao层的映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!--
引入dtd约束-->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace 是当前mapper对应的接口-->
<mapper namespace="com.etime.dao.StudentDao">
<!--select:指定当前的操作为查询-->
<!--id:当前标签对应的dao中 方法的名字-->
<!--resultType:指定当前查询得到的数据要封装成的类型-->
<select id="getAllStudents" resultType="com.etime.pojo.Student">
select * from student
</select>
</mapper>
5、编写核心配置文件mybatisConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--引入dtd约束-->
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--配置mybatis的环境-->
<environments default="development">
<!--配置环境-->
<environment id="development">
<!--配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<!--配置链接数据库的信息:使用的是 数据源[连接池]-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/sms"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--注册StudentDao接口映射文件位置-->
<mappers>
<mapper resource="mappper/StudentMapper.xml"></mapper>
</mappers>
</configuration>
6、编写测试代码
@Test
public void test02() throws IOException {
// 加载配置文件
InputStream in = Resources.getResourceAsStream("mybatisConfig.xml");
// 用于读取配置文件内容,生成SqlSessionFactory
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
// 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取StudentDao对象
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Student> allStudents = studentDao.getAllStudents();
System.out.println(allStudents);
sqlSession.close();
}
// 结果
[Student(id=101, name=李淑玲, gender=女, birthday=Tue Dec 28 00:00:00 CST 1999, s_class=1111, photo=2046184.jpg), Student(id=103, name=陆君, gender=男, birthday=Mon Jun 03 00:00:00 CST 1974, s_class=95031, photo=2049659.jpg), Student(id=105, name=匡明, gender=男, birthday=Thu Oct 02 00:00:00 CST 1975, s_class=95031, photo=2049660.jpg), Student(id=107, name=王丽, gender=女, birthday=Fri Jan 23 00:00:00 CST 1976, s_class=95033, photo=2049673.jpg), Student(id=108, name=曾华, gender=男, birthday=Thu Sep 01 00:00:00 CST 1977, s_class=95033, photo=2049675.jpg), Student(id=119, name=小母, gender=男, birthday=Wed Mar 01 00:00:00 CST 2023, s_class=1111, photo=2050004.jpg), Student(id=120, name=欧吧胡, gender=女, birthday=Tue Feb 14 00:00:00 CST 2023, s_class=1111, photo=2050010.jpg), Student(id=123, name=韩信, gender=男, birthday=Thu Mar 09 00:00:00 CST 2023, s_class=1113, photo=2050143.jpg), Student(id=124, name=孙悟空, gender=男, birthday=Thu Mar 02 00:00:00 CST 2023, s_class=1113, photo=2050230.jpg), Student(id=130, name=李白, gender=女, birthday=Sat Mar 18 00:00:00 CST 2023, s_class=1111, photo=2051054.jpg), Student(id=190, name=娜可露露, gender=女, birthday=Wed Jun 05 00:00:00 CST 2013, s_class=1111, photo=2051061.jpg), Student(id=191, name=露娜, gender=女, birthday=Fri Mar 17 00:00:00 CST 2023, s_class=1111, photo=2050074.jpg)]
Process finished with exit code 0
7、项目结构
三、Mybatis原理
1、执行原理图
2、配置文件分析
(1)核心配置文件-核心配置文件参数详解
-
environment标签的 id属性值 必须和 environments标签的default属性一致。
-
事务管理器
- JDBC事务类型。直接使用了JDBC的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
- MANAGED事务类型。从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。
<transactionManager type="MANAGED"> <property name="closeConnection" value="false"/> </transactionManager>
-
数据源 (DataSource)
- 描述:dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。大多数 mybatis 应用程序会按示例中的例子来配置数据源、虽然数据眼配置是可选的,但如果要启用延迟加载特性,就必须配置数据源。
- 内建的数据源类型(type=“[UNPOOLED|POOLED|JNDI]”)
- UNPOOLED
- 这个数据源的实现会每次请求时打开和关闭连接。
- 使用场景:虽然有点慢,但对那些数据库连接可用性要求不高的简单应用程序来说,是一个很好的选择。性能表现则依赖于使用的数据库,对某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形。
- POOLED
- 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。
- 这种处理方式很流行,能使并发 Web 应用快速响应请求。
- JNDI
- 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的数据源引用。
- UNPOOLED
-
mapper中的指定映射文件的位置的属性
- 作用:指定映射文件的位置
- resource
- resource=“mapper/StudentMapper.xml”
- 文件在多级目录中要用分隔符“/”隔开。
- class
- class=“com.etime.dao.StudentDao”
- 指定StudentDao接口文件位置,但此时StudentDao.xml必须和接口处在同一个包中并且文件名要相同。
(2)映射文件-映射文件参数详解
- namespace必须为接口的完全限定名(即包名+类名的格式)。
- select标签中的id必须和接口中声明的方法同名。
- 如果接口中方法有返回值,resyultType必须跟方法返回值一致并采用返回值的完全限定名来表示。
3、底层源码分析
步骤解析
-
利用Resources.getResourceAsStream()方法读取核心配置文件,该配置文件中注册数据源(dataSource)和 映射文件(mappers标签中的mapper子标签的resource属性)
-
InputStream in = Resources.getResourceAsStream("mybatisConfig.xml");
-
-
展开映射文件(StudentMapper.xml)中定义的查询方法、查询时所封装结果类型和所要执行的sql语句。
-
<select id="getAllStudents" resultType="com.etime.pojo.Student"> select * from student </select>
-
-
使用 构建者模式 SqlSessionFactoryBuilder类的build方法创建SqlSessionFactory对象,在build方法中从字节输入流中解析数据。
-
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
-
SqlSessionFactoryBuilder.java的build方法:
-
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { SqlSessionFactory var5; try { XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); var5 = this.build(parser.parse()); } catch (Exception var14) { throw ExceptionFactory.wrapException("Error building SqlSession.", var14); } finally { ErrorContext.instance().reset(); try { inputStream.close(); } catch (IOException var13) { } } return var5; }
-
-
XMLConfigBuilder的parse方法:
-
public Configuration parse() { if (this.parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); } else { this.parsed = true; this.parseConfiguration(this.parser.evalNode("/configuration")); return this.configuration; } }
-
-
XMLConfigBuilder的parseConfiguration方法:
-
private void parseConfiguration(XNode root) { try { this.propertiesElement(root.evalNode("properties")); Properties settings = this.settingsAsProperties(root.evalNode("settings")); this.loadCustomVfs(settings); this.loadCustomLogImpl(settings); this.typeAliasesElement(root.evalNode("typeAliases")); this.pluginElement(root.evalNode("plugins")); this.objectFactoryElement(root.evalNode("objectFactory")); this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); this.reflectorFactoryElement(root.evalNode("reflectorFactory")); this.settingsElement(settings); this.environmentsElement(root.evalNode("environments")); this.databaseIdProviderElement(root.evalNode("databaseIdProvider")); this.typeHandlerElement(root.evalNode("typeHandlers")); this.mapperElement(root.evalNode("mappers")); } catch (Exception var3) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3); } }
-
-
XMLConfigBuilder的mapperElement方法:
-
private void mapperElement(XNode parent) throws Exception { if (parent != null) { Iterator var2 = parent.getChildren().iterator(); while(true) { while(var2.hasNext()) { XNode child = (XNode)var2.next(); String resource; if ("package".equals(child.getName())) { resource = child.getStringAttribute("name"); this.configuration.addMappers(resource); } else { resource = child.getStringAttribute("resource"); String url = child.getStringAttribute("url"); String mapperClass = child.getStringAttribute("class"); XMLMapperBuilder mapperParser; InputStream inputStream; if (resource != null && url == null && mapperClass == null) { ErrorContext.instance().resource(resource); inputStream = Resources.getResourceAsStream(resource); mapperParser = new XMLMapperBuilder(inputStream, this.configuration, resource, this.configuration.getSqlFragments()); mapperParser.parse(); } else if (resource == null && url != null && mapperClass == null) { ErrorContext.instance().resource(url); inputStream = Resources.getUrlAsStream(url); mapperParser = new XMLMapperBuilder(inputStream, this.configuration, url, this.configuration.getSqlFragments()); mapperParser.parse(); } else { if (resource != null || url != null || mapperClass == null) { throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one."); } Class<?> mapperInterface = Resources.classForName(mapperClass); this.configuration.addMapper(mapperInterface); } } } return; }
-
**总结:**上述代码中我们可以看到创建了一个XMLConfigBuilder对象用来解析XML,把配置文件中所有标签及标签中属性值放封装Configuration对象中并返回SqlSessionFactory对象。
-
-
调用SqlSessionFactory对象的openSession方法返回一个SqlSession对象,SqlSessionFactory是一个接口,我们找到它的实现类DefaultSqlSessionFactory类,点击它的openSession方法,打开openSessionFromDataSource方法。
-
SqlSession sqlSession = sqlSessionFactory.openSession();
-
DefaultSqlSessionFactory.java的openSessionFromDataSource方法:
-
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; DefaultSqlSession var8; try { Environment environment = this.configuration.getEnvironment(); TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment); //根据环境的配置创建一个新的事务 tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); Executor executor = this.configuration.newExecutor(tx, execType); //创建DefaultSqlSession对象,即SqlSession对象 var8 = new DefaultSqlSession(this.configuration, executor, autoCommit); } catch (Exception var12) { this.closeTransaction(tx); throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12); } finally { ErrorContext.instance().reset(); } return var8; }
-
-
-
调用sqlSession.getMapper(StudentDao.class)方法返回一个StudentDao接口的代理类对象。
-
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
-
DefaultSqlSessionFactory.java的getMapper方法:
-
public <T> T getMapper(Class<T> type) { return this.configuration.getMapper(type, this); }
-
-
Configuration.java的getMapper方法:
-
public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return this.mapperRegistry.getMapper(type, sqlSession); }
-
-
MapperRegistry.java的getMapper方法:
-
public <T> T getMapper(Class<T> type, SqlSession sqlSession) { MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type); if (mapperProxyFactory == null) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } else { try { return mapperProxyFactory.newInstance(sqlSession); } catch (Exception var5) { throw new BindingException("Error getting mapper instance. Cause: " + var5, var5); } } }
-
-
mapperProxyFactory.java的newInstance方法:
-
public T newInstance(SqlSession sqlSession) { MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache); return this.newInstance(mapperProxy); }
-
-
四、mybatis实现CRUD
1、在StudentDao接口中定义方法
import com.etime.pojo.Student;
import java.util.List;
public interface StudentDao {
// 查询所有学生信息
List<Student> getAllStudents();
// 添加学生信息
int addStudent(Student student);
// 删除学生信息
int deleteStudentById(String sid);
// 修改学生信息
int updateStudent(Student student);
// 查询学生信息通过id
Student getStudentById(String sid);
// 统计学生总数
int getContRows();
}
2、在映射文件中添加设置
<?xml version="1.0" encoding="UTF-8" ?>
<!--
引入dtd约束-->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace 是当前mapper对应的接口-->
<mapper namespace="com.etime.dao.StudentDao">
<!--select:指定当前的操作为查询-->
<!--id:当前标签对应的dao中 方法的名字-->
<!--resultType:指定当前查询得到的数据要封装成的类型-->
<select id="getAllStudents" resultType="com.etime.pojo.Student">
select * from student
</select>
<!-- // 添加学生信息
int addStudent(Student student);
// 删除学生信息
int deleteStudentById(int sid);
// 修改学生信息
int updateStudent(Student student);
// 查询学生信息通过id
Student getStudentById(int sid);
// 统计学生总数
int getContRows();-->
<insert id="addStudent" parameterType="com.etime.pojo.Student">
insert into student(id,name,gender,birthday,s_class,photo) values(#{id},#{name},#{gender},#{birthday},#{s_class},#{photo});
</insert>
<delete id="deleteStudentById" parameterType="String">
delete from student where id=#{id};
</delete>
<update id="updateStudent" parameterType="com.etime.pojo.Student">
update student set name=#{name},gender=#{gender},birthday=#{birthday},s_class=#{s_class},photo=#{photo} where id=#{id};
</update>
<select id="getStudentById" parameterType="String" resultType="com.etime.pojo.Student">
select * from student where id=#{id};
</select>
<select id="getContRows" resultType="int">
select count(*) from student;
</select>
</mapper>
3、测试
@Test
public void test03() throws IOException {
// 加载配置文件
InputStream in = Resources.getResourceAsStream("mybatisConfig.xml");
// 用于读取配置文件内容,生成SqlSessionFactory
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
// 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取StudentDao对象
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Date date = Date.valueOf("2023-04-16");
int res = studentDao.addStudent(new Student("11", "小李", "男", date, "1011", null));
System.out.println("add res = " + res);
sqlSession.commit();
sqlSession.close();
}
@Test
public void test04() throws IOException {
// 加载配置文件
InputStream in = Resources.getResourceAsStream("mybatisConfig.xml");
// 用于读取配置文件内容,生成SqlSessionFactory
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
// 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取StudentDao对象
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
int res = studentDao.deleteStudentById("11");
System.out.println("delete res = " + res);
sqlSession.commit();
sqlSession.close();
}
@Test
public void test05() throws IOException {
// 加载配置文件
InputStream in = Resources.getResourceAsStream("mybatisConfig.xml");
// 用于读取配置文件内容,生成SqlSessionFactory
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
// 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取StudentDao对象
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = new Student("11", "li", "男", null, "1011", null);
int res = studentDao.updateStudent(student);
System.out.println("update res = " + res);
sqlSession.commit();
sqlSession.close();
}
@Test
public void test06() throws IOException {
// 加载配置文件
InputStream in = Resources.getResourceAsStream("mybatisConfig.xml");
// 用于读取配置文件内容,生成SqlSessionFactory
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
// 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取StudentDao对象
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = studentDao.getStudentById("11");
System.out.println("student = " + student);
sqlSession.close();
}
@Test
public void test07() throws IOException {
// 加载配置文件
InputStream in = Resources.getResourceAsStream("mybatisConfig.xml");
// 用于读取配置文件内容,生成SqlSessionFactory
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
// 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取StudentDao对象
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
int contRows = studentDao.getContRows();
System.out.println("contRows = "+ contRows);
sqlSession.close();
}
4、提取工具类SqlSessionUtil.java
package com.etime.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.IOException;
import java.io.InputStream;
public class SqlSessionUtil {
private static SqlSession sqlSession;
static {
InputStream in = null;
try {
// 加载配置文件
in = Resources.getResourceAsStream("mybatisConfig.xml");
// 用于读取配置文件内容,生成SqlSessionFactory
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
// 获取SqlSession
sqlSession = sqlSessionFactory.openSession();
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
return sqlSession;
}
}
5、测试工具类SqlSessionUtil
@Test
public void test02() throws IOException {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
// 获取StudentDao对象
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Student> allStudents = studentDao.getAllStudents();
System.out.println(allStudents);
sqlSession.close();
}
五、mybatis的参数处理
1、parameterType 配置参数
(1)参数的使用说明
- 作用:SQL语句传参,使用标签的 parameterType 属性来设定。
- 参数类型 :基本类型,引用类型(例:String)、实体类类型(POJO 类)、实体类的包装类
(2)参数配置的注意事项
- 基本类型和String:直接写类型名称 或 包名.类名的方式(例:java.lang.String)
- 实体类类型:目前我们只能使用完全限定类名
- 原因:是mybaits在加载时已经把常用的数据类型注册了别名,从而我们在使用时可以不写包名,而我们的是实体类并没有注册别名,所以必须写全限定类名。
(3)mybatis 官方文档(参数)
别名 | 映射的类型 |
---|---|
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
2、传递 pojo 包装对象
开发中通过 pojo 传递查询条件 ,查询条件是综合的查询条件,不仅包括学生查询条件还包括其它的查询条件(比如将学生的老师也作为查询条件),这时可以使用包装对象传递输入参数,Pojo 类中包含 pojo。
(1)编写QueryVo
- 学生类
package com.etime.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Student {
private int id;
private String name;
private String gender;
private Date birthday;
private String s_class;
private String photo;
}
- 教师类
package com.etime.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Teacher {
private int tid;
private String tname;
}
- QueryVo类
package com.etime.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class QueryVo {
private Student student;
private Teacher teacher;
}
(2)编写接口StudentDao方法
// 查询某个老师授课的男学生有哪些
List<Student> getStudentByQueryVo(QueryVo queryVo);
(3)编写持久层接口StudentMapper.xml
<select id="getStudentByQueryVo" parameterType="com.etime.pojo.QueryVo" resultType="com.etime.pojo.Student">
select * from student s,teacher t,studentteacher st where s.sid=st.sid and t.tid=st.tid and t.tname=#{teacher.tname} and s.gender=#{student.gender}
</select>
(4)测试
@Test
public void test10(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = new Student(199, "李一111", "男", null, "1111", "li1.jpg");
Teacher teacher = new Teacher(0,"jacy");
QueryVo queryVo = new QueryVo(student,teacher);
List<Student> list = studentDao.getStudentByQueryVo(queryVo);
list.forEach(System.out::println);
sqlSession.close();
}
3、map 集合数据作为参数的处理方式
(1)在接口StudentDao中添加方法 参数为 Map 集合
// 查询名字为"li李"的男生
List<Student> getStudentByGenderAndName(Map<String,Object> map);
(2)在映射文件 StudentMapper中 配置信息
<select id="getStudentByGenderAndName" parameterType="Map" resultType="com.etime.pojo.Student">
select * from student where name=#{name} and gender=#{gender}
</select>
(3)测试
@Test
public void test11(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Map<String,Object> map = new HashMap<>();
map.put("name","li李");
map.put("gender","男");
List<Student> list = studentDao.getStudentByGenderAndName(map);
list.forEach(System.out::println);
sqlSession.close();
}
4、#{} 和 ${}的区别
#{} | ${} |
---|---|
预编译处理 | 字符串替换 |
mybatis在处理#{},会将SQL中的#{}替换成?号,调用 PreparedStatement的set方法来赋值 | mybatis在处理 时,把 {}时,把 时,把{}替换成变量的值 |
使用#{}可以有效的防止SQL注入,提高系统安全性 |
六、mybatis模糊查询
- 三种模糊查询方式
1、在接口StudentDao编写三种方法
/*
模糊查询
*/
List<Student> getStudentByName1(String name);
List<Student> getStudentByName2(String name);
List<Student> getStudentByName3(String name);
2、在映射文件中编写对应SQL方法
(1)配置占位符方式-#{}
<select id="getStudentByName1" parameterType="String" resultType="com.etime.pojo.Student">
select * from student where name like #{name}
</select>
(2)配置拼接字符串方式-${}
<!--将方式1的#{name},改成${name}。
注意:如果用模糊查询的这种方式,那么${name}的写法
就是固定的,不能写成其他名字-->
<select id="getStudentByName2" parameterType="String" resultType="com.etime.pojo.Student">
select * from student where name like '%${name}%'
</select>
(3)配置MySQL函数方式-concat()
<select id="getStudentByName3" parameterType="String" resultType="com.etime.pojo.Student">
select * from student where name like concat('%',#{name},'%')
</select>
3、模糊查询测试
@Test
public void test12(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
String name = "%李%";
List<Student> list = studentDao.getStudentByName1(name);
list.forEach(System.out::println);
sqlSession.close();
}
@Test
public void test13(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Student> list = studentDao.getStudentByName2("李");
list.forEach(System.out::println);
sqlSession.close();
}
@Test
public void test14(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Student> list = studentDao.getStudentByName3("李");
list.forEach(System.out::println);
sqlSession.close();
}
七、mybatis结果封装
1、resultType结果类型
(1)resultType属性介绍
- resultType 属性可以指定结果集的类型。
- 支持基本类型和实体类类型。
- 注意:
- 它和 parameterType 一样,如果注册过类型别名的,可以直接使用别名。
- 没有注册过的必须使用全限定类名。
- 实体类中的属性名称必须和查询语句中的列名保持一致,否则无法实现封装。
2、resultType属性的使用
(1)基本类型
前面的示例使用了,此处省略,去前面看。
(2)实体类型
前面的示例使用了,此处省略,去前面看。
(3)特殊情况
- 情况:若修改Student类中的某个属性,例:sid改为stuId。
- 分析:此时查询出的结果没有把表中的sid值映射到stuId属性中,因为属性和表中的列名不一致,内部无法用反射技术进行映射,所以为空。
a.实体类
package com.etime.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Student {
private int stuId;
private String name;
private String gender;
private Date birthday;
private String s_class;
private String photo;
}
b.修改映射文件StudentDao的SQL
- 解决办法:修改映射配置,采用别名设置,让结果集中的列与实体类中的属性对应。
<select id="getAllStudents" resultType="Student">
select id stuId,name,gender,birthday,s_class,photo from student;
</select>
c.测试
@Test
public void test01() throws IOException {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Student> allStudents = studentDao.getAllStudents();
System.out.println(allStudents);
allStudents.forEach(System.out::println);
sqlSession.close();
}
2、resultMap自定义结果类型
(1)resultMap标签介绍
- resultMap 标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系。
- 实现封装
- 在 select 标签中使用 resultMap 属性指定引用。
- 同时 resultMap 可以实现将查询结果映射为复杂类型的 pojo,比如在查询结果映射对象中包括 pojo 和 list 实现一对一查询和一对多查询。
(2)resultMap的使用
a.修改Student实体类,属性名与表不对应
package com.etime.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Student {
private int stuId;
private String stuName;
private String stuGender;
private int stuAge;
private String stuEmail;
private String stuPhoto;
}
b.在接口StudentDao.java中编写方法
List<Student> getAllStudents();
c.在映射文件StudentDao.xml中编写SQL
<select id="getAllStudents" resultMap="stuMap">
select * from student
</select>
<resultMap id="stuMap" type="com.etime.pojo.Student">
<id property="stuId" column="sid"></id>
<result property="stuName" column="sname"></result>
<result property="stuGender" column="sgender"></result>
<result property="stuAge" column="sage"></result>
<result property="stuEmail" column="semail"></result>
<result property="stuPhoto" column="sphoto"></result>
</resultMap>
d.测试
@Test
public void test01() throws IOException {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Student> allStudents = studentDao.getAllStudents();
System.out.println(allStudents);
allStudents.forEach(System.out::println);
sqlSession.close();
}
e.resultType 和 resultMap
resultType | resultMap |
---|---|
结果类型 | 映射结果集与类中属性对应关系。 |
f.resultMap
标签 | 描述 |
---|---|
type | resultMap返回的类型 |
id | 指定主键字段 |
result | 指定非主键字段 |
column | 指定数据库列名 |
property | 指定实体类属性名称 |
type=“com.etime.pojo.Student”>
###### d.测试
```java
@Test
public void test01() throws IOException {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Student> allStudents = studentDao.getAllStudents();
System.out.println(allStudents);
allStudents.forEach(System.out::println);
sqlSession.close();
}
e.resultType 和 resultMap
resultType | resultMap |
---|---|
结果类型 | 映射结果集与类中属性对应关系。 |
f.resultMap
标签 | 描述 |
---|---|
type | resultMap返回的类型 |
id | 指定主键字段 |
result | 指定非主键字段 |
column | 指定数据库列名 |
property | 指定实体类属性名称 |