这是我参与「第三届青训营 -后端场」笔记创作活动的第2篇笔记
一、数据库中准备工作
首先需要一张数据库的表
新建数据库:Mydatabase
新建表:tbl_employee
表中新建四个字段:id,lastName,email,age
插入一条记录:1,tom,Tom@ee.com,18
二、连接数据库并查询一条记录
1. 写一个与数据库中表对应的类
Employee.Class
public class Employee {
private int id;
private String lastName;
private String email;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
2. 导入 jar 包(Maven 方式)
在 POM.xml 中插入以下这段:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>
版本号可去官网查看
3. 创建一个Mybatis的全局配置文件
这个全局配置文件的作用是连接数据库
一般起名为:mybatis-config.xml
主要改 dataSource 标签和 mappers 标签里面的配置
<?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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<!-- 下面一般只改value值 -->
<!-- 这一行为了说明数据库框架,postgresql的话就写下面这个 -->
<property name="driver" value="org.postgresql.Driver" />
<!-- 这一行为了说明连接的哪个数据库,默认的端口就是5432,数据库是自己创建的Mydatabase -->
<property name="url" value="jdbc:postgresql://localhost:5432/Mydatabase" />
<!-- 这一行为了说明连接的哪个数据库的用户名,一般默认就是postgres -->
<property name="username" value="postgres" />
<!-- 这一行为了说明连接数据库所需要的密码 -->
<property name="password" value="Zhou1104" />
</dataSource>
</environment>
</environments>
<!--
<mappers>
这个SQL映射文件后面会讲到;
将我们写好的sql映射文件(EmployeeMapper.xml)一定要注册到全局配置文件(mybatis-config.xml)中;
注册的方法就是使用<mappers>标签;
-->
<mappers>
<mapper resource="EmployeeMapper.xml" />
</mappers>
</configuration>
4. 在 Main 函数中引入配置文件
在 Main 函数中需要创建一个 SqlSessionFactory 的对象来引入全局配置文件(mybatis-config.xml)
//获取全局配置文件中的字符
String resource = "mybatis-config.xml";
//根据字符形成数据流
InputStream inputStream = Resources.getResourceAsStream(resource);
//根据数据流产生SqlSession工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//根据SqlSession工厂创建SqlSession对象,这个实例能执行已经映射的Sql语句
SqlSession openSession = sqlSessionFactory.openSession();
5. 创建 xml 映射文件(与全局配置文件不同)
映射文件作用主要是为了连接相应的类和方法
这个映射文件的名称为 Employee.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">
<!-- namespace: 这个映射文件的名称空间 -->
<mapper namespace="abc">
<!-- id:这个映射文件的唯一标识符 resultType:查询结果的返回值,即将查询结果返回到一个类中 -->
<select id="selectEmp" resultType="com.Joe.Bean.Employee">
<!-- 从表tbl_employee中选择id值为#{id}的lastName -->
<!-- id写成这样:#{id},是为了将所需要的id值传进来 -->
select lastName from tbl_employee where id = #{id}
</select>
</mapper>
这个映射文件需要在全局配置文件中进行注册
在上面的全局配置文件(mybatis-config.xml)代码中,标签就是为了注册映射文件
6. 在 Main 函数中进行数据库中数据的查询,并将查询的结果放入 Employee 类中
/*
openSession.selectOne()方法是为了查询表中的一条记录
参数1:指明写Sql查询语句的xml映射文件
abc.selectEmp是指的这个xml映射文件的唯一名称(不是文件名,可以理解为这个xml文件自己的名字)
其中abc是名称空间(namespace)的值
selectEmp是唯一标识(id)的值
参数2:传入Sql语句中所需要的值
这个例子中就是将id为1传了进去
*/
Employee employee = openSession.selectOne("abc.selectEmp", 1);
System.out.println(employee.getLastName());
7. 主函数代码
package com.Joe.Main;
import com.Joe.Bean.Employee;
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 Main {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession openSession = sqlSessionFactory.openSession();
try {
Employee employee = openSession.selectOne("abc.selectEmp", 1);
System.out.println(employee.getLastName());
}
finally {
openSession.close();
}
}
}
输出结果:
Tom
8. 以上方法的缺点
按照以上方法查询数据库时,使用的是 Mybatis 封装好的方法 selectOne ( ),代码如下
/*
openSession.selectOne()方法是为了查询表中的一条记录
参数1:指明写Sql查询语句的xml映射文件
abc.selectEmp是指的这个xml映射文件的唯一名称(不是文件名,可以理解为这个xml文件自己的名字)
其中abc是名称空间(namespace)的值
selectEmp是唯一标识(id)的值
参数2:传入Sql语句中所需要的值
这个例子中就是将id为1传了进去
*/
Employee employee = openSession.selectOne("abc.selectEmp", 1);
在这个方法中,能够实现条件查询的参数只有一个,也就是第二个参数
完全可以通过这个方法进行单一条件的查询,就比如例子中查询 id 值为 1 的记录,这是一个单一条件
但假如想要进行组合条件查询的话,这个方法就无能为力了
比如要查询 id 值小于 10 并且 age 值小于 20 的记录,那这个方法很显然做不到
那可不可以用 Mybatis 封装好的其它方法?
我不知道,或许可以,或许 Mybatis 将所有可能使用的查询条件组合方式都考虑到了,但我没去查,也没必要查
因为各式各样的查询(包括插入、更新)数据库的方法完全可以由我们自己去定义,自己去写
三、通过接口来自定义数据库的操作方法
1. 声明方法的接口
与上面不同的是,现在我们要使用自己的方法去查询、插入和更新数据库
这就需要有一个接口专门声明这些方法
EmployeeMapper.Interface
public interface EmployeeMapper {
//根据id来查询数据库中记录的方法
public Employee getEmpById(int id);
//向数据库中插入记录的方法
public void setEmp(int id, String lastName, String email, int age);
}
接口中的这两个方法各有特点:
-
getEmpById ( ) 方法:返回值是 Employee,而 Employee 类中的属性正是数据库中表 tbl_employee 的所有字段
也就是说,这个方法的目的是将数据库中查询到的结果放在一个 Employee 对象中进行存储,而并不是直接显示给用户
那 Employee 类中可以创建一个方法,来显示 Employee 对象中的属性值,这个属性值就是从数据库中查询到的表记录
Employee 相当于做了一次中间商
-
setEmp ( ) 方法:返回值为空,意思是只需要将参数设置好,这个方法就能直接把参数的值写到数据库中,不需要任何中间商
2. 修改 xml 映射文件
之前的映射文件是这么写的
Employee.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">
<!-- namespace: 这个映射文件的名称空间 -->
<mapper namespace="abc">
<!-- id:这个映射文件的唯一标识符 resultType:查询结果的返回值,即将查询结果返回到一个类中 -->
<select id="selectEmp" resultType="com.Joe.Bean.Employee">
select lastName from tbl_employee where id = #{id}
</select>
</mapper>
现在需要修改名称空间(namespace)和唯一标识符(id)
名称空间:改为接口的全路径
唯一标识符:改为接口中的方法名
代码如下:
<?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: 名称空间改为接口的全路径 -->
<mapper namespace="com.Joe.Service.EmployeeMapper">
<!-- select方法 -->
<!-- id:唯一标识符改为接口中方法名 -->
<select id="getEmpById" resultType="com.Joe.Bean.Employee">
select id, lastName, email, age from tbl_employee where id = #{id};
</select>
<!-- insert方法 -->
<insert id="setEmp">
insert into tbl_employee (id, lastName, email, age) values (#{id}, #{lastName}, #{email}, #{age});
</insert>
</mapper>
<!--
说明:
(id, lastName, email, age) 中的值对应的是数据库中表的字段
(#{id}, #{lastName}, #{email}, #{age}) 中的值对应的是接口中函数的参数
-->
3. Main 函数实现
Main.Class
public class Main {
public static void main(String[] args) throws IOException {
//创建openSession(必不可少)
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession openSession = sqlSessionFactory.openSession();
try {
//创建接口的代理对象emploeeMapper,所有方法都是代理对象去实现
EmployeeMapper employeeMapper = openSession.getMapper(EmployeeMapper.class);
//向数据库中执行插入(不需要返回值)
employeeMapper.setEmp(2, "Tom", "Tom@ee.com", 23);
//提交插入结果(insert和update必不可少)
openSession.commit();
//获取id值为2的记录,并储存在类Employee的对象employee中(需要返回值)
Employee employee = employeeMapper.getEmpById(2);
//输出对象employee中的属性值
System.out.println(employee.getId() + " " + employee.getLastName() + " " +
employee.getEmail() + " " + employee.getAge());
}
finally {
openSession.close();
}
}
}
输出结果:
2 Tom Tom@ee.com 23
四、其它知识点
1. SqlSession
-
代表和数据库的一次会话,用完必须关闭
-
SqlSession 是个非线程安全
即不能直接在 Main 方法里这么定义:
private SqlSession sqlSession;因为如果这么定义之后,可能会被别的线程拿去使用
所以必须要即用即定义
String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //即用即定义 SqlSession openSession = sqlSessionFactory.openSession();
2. Mapper接口
Mapper 接口没有实现类,但Mybatis会为这个接口创建一个代理对象
通过代理对象绑定 xml 文件和 Mapper 接口
3. 两个配置文件
-
mybatis-config.xml:
数据库连接池信息,事务管理信息
-
Mapper.xml:
保存了每一个 sql 语句的映射信息