Mybatis快速入门
目录
1.一条完整的Mybatis使用过程
目录结构:
1.创建数据库和表,并插入数据
CREATE DATABASE `mybatis` /*!40100 DEFAULT CHARACTER SET utf8mb4 */
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4
并插入数据:
2.新建maven项目,添加依赖和插件
新建maven项目(quickstart模板)
添加mybatis依赖
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!--mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
然后要添加 资源文件的指定
<!--添加资源文件的锁定-->
<build>
<resources>
<!--锁定java目录下的文件-->
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
<!--锁定文件修改之后,需要重新锁定resources下的文件-->
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</build>
为什么要添加资源文件的指定?
来测试一下,不添加资源文件指定:
先clean以下之前编译结果,测试一下添加资源文件锁定后的编译结果:
3.idea添加数据库可视化操作
4.写jdbc属性文件
jdbc.diverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=admin
5.核心配置文件(配置数据源、jdbc连接参数、注册mapper文件)
SqlMapConfig.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">
核心配置文件内容:
<?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>
<!--读取属性文件——JDBC.properties
标签属性:
resources:从resources目录下找指定文件
url:使用绝对路径加载指定文件
-->
<properties resource="jdbc.properties"></properties>
<!--配置数据库的环境变量(数据库连接配置)
标签属性:
default:指定生效的<environment
id:对接<environments的default属性
-->
<environments default="development">
<!--开发时使用的数据库配置-->
<environment id="development">
<!--配置事务管理器
type:指定事务管理的方式
JDBC:事务的控制交给程序员处理
MANAGED:由容器(spring)管理事务
-->
<transactionManager type="JDBC"></transactionManager>
<!--配置数据源
type:指定不同的配置方式
JNDI:java命名目录接口,在服务端进行数据库连接池的管理
POOLED:使用数据库连接池
UNPOLLED:不使用数据库连接池
-->
<dataSource type="POOLED">
<!--数据库连接的基本参数
diver、url、username、password
-->
<property name="driver" value="${jdbc.diverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
<!--本机数据库配置-->
<environment id="home">
<transactionManager type=""></transactionManager>
<dataSource type=""></dataSource>
</environment>
<!--上限数据库配置-->
<environment id="online">
<transactionManager type=""></transactionManager>
<dataSource type=""></dataSource>
</environment>
</environments>
<!--注册mapper文件-->
</configuration>
http://mybatis.org/dtd/mybatis-3-config.dtd 这个文档中规定了此配置文件中可以书写哪些标签
<!ELEMENT configuration (properties?, settings?, typeAliases?, typeHandlers?, objectFactory?, objectWrapperFactory?, reflectorFactory?, plugins?, environments?, databaseIdProvider?, mappers?)>
为什么要用数据库连接池?
6.编写数据库实体类
package org.example.pojo;
/**
* @Description:
* @Author:cjy
* @Data:2022/5/3
* @Version:
*/
public class Student {
private Integer id;
private String name;
private String email;
private Integer age;
/*
无参构造方法
*/
public Student() {
}
/*
全参的构造方法
*/
public Student(Integer id, String name, String email, Integer age) {
this.id = id;
this.name = name;
this.email = email;
this.age = age;
}
/*
不包括主键的构造方法
做增加操作时,主键不需要给值
*/
public Student(String name, String email, Integer age) {
this.name = name;
this.email = email;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", age=" + age +
'}';
}
}
7.编写映射文件(SQL语句)
StudentMapper.xml
先加入约束头文件
<?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">
映射文件的内容:
<?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标签:整个文件的标签,用来开始和结束xml文件
属性:
namespace:指定命名空间(相当于包名),用来区分不同的mapper
-->
<mapper namespace="test">
<!--
完成查询所有学生的功能
List<Student> getAll——测试类查询
resultType:指定查询返回结果集的类型(全限定名),如果是集合,则必须是泛型的类型
parameterType:方法中有参数,则需要此属性指定参数的类型
-->
<select id="getAll" resultType="org.example.pojo.Student">
/*不使用*查询,因为*查询的效率极低*/
select id,name,email,age
from student
</select>
</mapper>
注意: 写完了映射文件之后,是无法直接使用映射文件的,还需要去核心配置文件中注册!!
在核心文件中注册:
<!--注册mapper文件
resource:从resources目录下找到指定的文件加载
url:使用绝对路径注册
class:动态代理方式下载注册
-->
<mappers>
<mapper resource="StudentMapper.xml"></mapper>
</mappers>
</configuration>
http://mybatis.org/dtd/mybatis-3-mapper.dtd 这个文档中规定了此映射文件中可以书写哪些标签
<!ELEMENT mapper (cache-ref | cache | resultMap* | parameterMap* | sql* | insert* | update* | delete* | select* )+>
8.测试类
package org.example;
public class AppTest
{
@Test
public void test() throws IOException {
//使用文件流读取核心配置文件SqlMapConfig.xml
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象
SqlSession sqlSession = factory.openSession();
//完成查询操作
List<Student> list = sqlSession.selectList("test.getAll");
list.forEach(student -> System.out.println(student));//输出查询结果
//关闭sqlSession,还回数据库连接池
sqlSession.close();
}
}
为什么要用 List<Student> 来存储查询数据?
因为查询结果是一个student对象,而mybatis会在底层帮我们将查询结果封装为一个对象放进list中。
注意,就算只查询一个字段,如name,返回结果依然是Student对象
如:
在映射文件中加入一条语句
<!--
按照id来进行查询
mybatis中Integer的别名是_int或integer,String的别名为string
-->
<select id="getOneById" parameterType="_int" resultType="string">
select name
from student
where id=#{id}
</select>
测试类:
@Test
public void test1() throws IOException {
//使用文件流读取核心配置文件SqlMapConfig.xml
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象
SqlSession sqlSession = factory.openSession();
//完成查询操作
String name = sqlSession.selectOne("test.getOneById",1);
System.out.println(name);
//关闭sqlSession,还回数据库连接池
sqlSession.close();
}
2.Mybatis的增删改查
1.查询
1.查询所有字段
映射文件:
<select id="getAll" resultType="org.example.pojo.Student">
select id,name,email,age
from student
</select>
测试类:
@Test
public void test() throws IOException {
//使用文件流读取核心配置文件SqlMapConfig.xml
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象
SqlSession sqlSession = factory.openSession();
//完成查询操作
List<Student> list = sqlSession.selectList("test.getAll");
list.forEach(student -> System.out.println(student));//输出查询结果
//关闭sqlSession,还回数据库连接池
sqlSession.close();
}
2.查询单个字段
<select id="getOneById" parameterType="_int" resultType="string">
select name
from student
where id=#{id}
</select>
测试类:
@Test
public void test1() throws IOException {
//使用文件流读取核心配置文件SqlMapConfig.xml
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象
SqlSession sqlSession = factory.openSession();
//完成查询操作
String name = sqlSession.selectOne("test.getOneById",1);
System.out.println(name);
//关闭sqlSession,还回数据库连接池
sqlSession.close();
}
3.模糊查询
映射文件:
<!--模糊查询
List<Student> getByName
-->
<select id="getByName" parameterType="string" resultType="org.example.pojo.Student">
select id,name,email,age
from student
where name like '%${name}%'
</select>
测试类:
@Test
public void test() throws IOException {
//使用文件流读取核心配置文件SqlMapConfig.xml
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象
SqlSession sqlSession = factory.openSession();
//完成查询操作
List<Student> list = sqlSession.selectList("test.getByName","张");
list.forEach(student -> System.out.println(student));//输出查询结果
//关闭sqlSession,还回数据库连接池
sqlSession.close();
}
2.增加
映射文件:
<!--增加学生
int insert(Student stu)
-->
<insert id="insert" parameterType="org.example.pojo.Student">
insert into student (name,email,age)
values (#{name},#{email},#{age})
</insert>
测试类:
@Test
public void test() throws IOException {
//使用文件流读取核心配置文件SqlMapConfig.xml
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象
SqlSession sqlSession = factory.openSession();
//调用方法
int num = sqlSession.insert("test.insert",new Student(" 刘一","45951456@126.com",19));
//********************增删改之后,必须手动提交事务*********************
sqlSession.commit();
sqlSession.close();
}
3.删除
<!--删除学生
int delete(Integer id);
-->
<delete id="delete" parameterType="int">
delete from student
where id=#{id}
</delete>
@Test
public void test2() throws IOException {
//使用文件流读取核心配置文件SqlMapConfig.xml
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象
SqlSession sqlSession = factory.openSession();
//调用方法
int num = sqlSession.delete("test.delete",5);
sqlSession.commit();
sqlSession.close();
}
4.更改
<!--更新学生
int update(Integer id);
-->
<update id="update" parameterType="org.example.pojo.Student">
update student
set name=#{name},email=#{email},age=#{age}
where id=#{id}
</update>
@Test
public void test2() throws IOException {
//使用文件流读取核心配置文件SqlMapConfig.xml
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象
SqlSession sqlSession = factory.openSession();
//调用方法
int num = sqlSession.update("test.update",new Student(4,"赵七","46465@qq.com",20));
sqlSession.commit();
sqlSession.close();
}
3.mybatis数据映射
4.mybatis对象分析
@Test
public void test() throws IOException {
//使用文件流读取核心配置文件SqlMapConfig.xml
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象
SqlSession sqlSession = factory.openSession();
//完成查询操作
List<Student> list = sqlSession.selectList("test.getAll");
list.forEach(student -> System.out.println(student));//输出查询结果
//关闭sqlSession,还回数据库连接池
sqlSession.close();
}
Resources类
- 解析 SqlMapConfig.xml 文件,创建出相应的对象
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory 接口
- DefaultSqlSessionFactory 实现类,此类创建出DefaultSqlSession(SqlSession的实现类)
SqlSessionFactoryBuilder类
- SqlSessionFactory对象(DefaultSqlSessionFactory)由SqlSessionFactoryBuilder的
build()
创建。
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession接口
- DefaultSqlSession 实现类,此类由DefaultSqlSession创建
- 这个实现类可以进行增删查改以及事务操作
Executor接口
- DefaultSqlSession 通过调用Executor执行器来执行sql语句
5.简化之前的测试代码
没有简化前的测试代码:
@Test
public void test() throws IOException {
//使用文件流读取核心配置文件SqlMapConfig.xml
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象
SqlSession sqlSession = factory.openSession();
//完成查询操作
List<Student> list = sqlSession.selectList("test.getAll");
list.forEach(student -> System.out.println(student));//输出查询结果
//关闭sqlSession,还回数据库连接池
sqlSession.close();
}
先将固定写法部分封装为一个方法
//设置为全局变量
SqlSession sqlSession;
@Before //在所有@Test方法执行前先执行的方法
public void openSqlSession() throws IOException {
//使用文件流读取核心配置文件SqlMapConfig.xml
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//创建SqlSession对象
sqlSession = factory.openSession();
}
@After
public void closeSqlSession(){
sqlSession.close();
}
其他测试方法的写法:
@Test
public void test() throws IOException {
//完成查询操作
List<Student> list = sqlSession.selectList("test.getAll");
list.forEach(student -> System.out.println(student));//输出查询结果
}
6.优化映射文件——为实体类注册别名
未优化前的映射文件的查询语句:
<select id="getAll" resultType="org.example.pojo.Student">
/*不使用*查询,因为*查询的效率极低*/
select id,name,email,age
from student
</select>
1.单个实体类别名的注册
在核心配置文件 SqlMapConfig.xml中去注册Student类的别名
<!--注册实体类的别名-->
<typeAliases>
<!--单个实体类别名的注册-->
<typeAlias type="org.example.pojo.Student" alias="student"></typeAlias>
</typeAliases>
然后就可以将映射文件中的 org.example.pojo.Student 更改为 student
<select id="getAll" resultType="student">
/*不使用*查询,因为*查询的效率极低*/
select id,name,email,age
from student
</select>
2.批量注册
当实体包下面的类有很多的时候(即数据库里面有很多张表),就用批量注册去注册这个包下的实体类的别名。
<typeAliases>
<!--批量注册别名
别名是类名的驼峰命名法(规范)
org.example.pojo包下的类都会自动根据上述规范取别名
如:Student的别名就是student
-->
<package name="org.example.pojo"/>
</typeAliases>
7.设置日志输出查看底层执行
<!--设置日志输出底层执行的代码-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
运行下列测试代码:
@Test
public void test3() throws IOException {
//完成查询操作
List<Student> list = sqlSession.selectList("test.getAll");
list.forEach(student -> System.out.println(student));//输出查询结果
}
查看控制台输出: