JavaEE笔记(四):初学MyBatis的使用
一、概念基础
1. J2EE结构
三层结构
- 表示层(Presentation)
- 业务逻辑层(Business Logic)
- 基础架构层(Infrastructure)
五层体系
- 表示层(Presentation)
- 控制/中介层(Controller/Mediator)
- 领域层(Domain)
- 数据持久层(Data Persistence)
- 数据源层(Data Source)
2. Mybatis
- MyBatis:是一个支持普通 SOL 查询、存储过程以及高级映射的持久层框架
- MyBatis 框架也称为 ORM框架
3. ORM框架
-
ORM(Object/Relational Mapping ):对象关系映射
-
ORM 就是通过实例对象的语法,完成关系型数据库的操作的技术
-
ORM 目的:为了解决面向对象与关系型数据库中数据类型不匹配
它通过描述Java 对象与数据库表之间的映射关系,自动将 Java 应用程序中的对象持久化到关系型数据库的表中
-
面向对象编程把所有实体看成对象(object)
-
关系型数据库则是采用实体之间的关系(relation)连接数据
-
ORM 把数据库映射成对象
- 数据库的表(table) --> 类(class)
- 记录(record,行数据)–> 对象(object)
- 字段(field)–> 对象的属性(attribute)
4. 持久化
- 持久(Persistence):把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘 )
- PO(Persisent Object ):持久化对象
- POJO ( Plain Old Java Object):普通 Java 对象
- 持久化的主要应用:将内存中的数据存储在关系型的数据库中,当然也可以存储在磁盘文件中、XML数据文件中等等
- 持久层(Persistence Layer)/ 数据访问层(Data Access Layer):专注于实现数据持久化应用领域的某个特定系统的一个逻辑层面,将数据使用者和数据实体相关联
问题:数据访问层(Data Access Layer)和数据持久层(Data Persistence Layer)是一样的吗?
-
百科: 数据访问层又称为DAL层,有时候也称为是持久层,其功能主要是负责数据库的访问(也就是:是一样的)
-
网络上暂且搜到的两种看法:
-
数据访问层只管理数据库的链接和操作,数据和数据库是同步的
持久层包含了数据访问层,做分布式必须在数据访问层做
-
只是不同的说法而已,经典的三层架构
表示层->业务逻辑层->持久层(数据访问层)
-
-
大多数说法都是两者是一样的,因此,暂且认为两者只是说法上的差异
参考资料:
The Data Access Layer (DAL) Explained
5. 数据持久层(DAO层)
-
DAO(Data Access Object):数据访问对象
-
数据访问对象:是一个面向对象的数据库接口
-
DAO类:都是进行数据操作的类, 是对于数据库中的数据做增删改查等操作的代码。
-
在Spring MVC中,对数据库的访问操作在数据持久层(DAO层)
-
规划DAO层时,一般来说
-
先规划DAO层的类的接口,接口声明了具体的数据库访问操作方法
DAO层的类的接口位置:一般放置在项目源代码的dao包下
在项目src目录下新建dao包,在dao包下新建接口类
-
方法的实现由具体数据库操作类来完成
一般在mapper中实现接口
-
Service层需要对数据库进行访问时,只需要调用DAO层的接口就可以,而不用关心具体的实现类
-
二、前期准备
- 连接数据库(在Navicat中)
- 在IDEA中下载Lombok、MyBatisX
三、程序结构
四、流程
1. new project
-
选择Spring Initializv
-
到Dependencies中
- Developer Tools中选择Lombok
- Web中选择Spring Web
- Template Engines中选择Apache Freemarker
- SQL中选择Mybatis Framework、MySQL Driver
2. 修改配置文件
mybatis.mapper-locations
是Mybatis映射文件的位置spring.datasource.url
是配置数据库连接属性
//路径\src\main\resources\application.properties
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
mybatis.mapper-locations=classpath:/mapper/*.xml
mybatis.type-aliases-package=com.entity
# spring boot集成mybatis的方式打印sql
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
3. 构建起框架
- 新建一个名为entity(或者叫model)的Directory放置对应表的属性DAO层的类(也就是对应着数据库的表):(路径\src\main\java\com\entity)
- 新建一个名为dao的Directory放置DAO层的类的接口:(路径:\src\main\java\com\dao)
- 新建一个名为mapperl的Directory放置SQL映射文件:(路径:\src\main\resources\mapperl)
4. entity/model
- @Data : 注解在类上, 为类提供读写属性, 此外还提供了 equals()、hashCode()、toString() 方法
- 注意:使用@Data要在IDEA中添加Lombok插件
- 实体类的属性和表的字段名称一一对应
//路径:\src\main\java\com\entity\Customer.java
package com.entity;
import lombok.Data;
@Data
public class Customer {
Integer id;
String username;
String jobs;
String phone;
}
- 持久化类 Customer 与普通的 JavaBean 并没有什么区别,只是其属性字段与数据库中的表字段相对应
- 实际上, Customer 就是一个 POJO (普通 Java 对象)
- MyBatis 就是采用 POJO 作为持久化类来完成对数据库操作的
5. dao
- 数据库访问方法
- @Repository:用于标注数据访问组件,即DAO组件
参考:@Component, @Repository, @Service的区别
@Component, @Repository, @Service的区别
@Repository
会被作为持久层操作(数据库)的bean来使用@Component
就是跟<bean>
一样,可以托管到Spring容器进行管理。`@Service
,@Controller
,@Repository
= {@Component
+ 一些特定的功能}。这个就意味着这些注解在部分功能上是一样的@Component
是通用注解,其他三个注解是这个注解的拓展 ,并且具有了特定的功能@Repository
注解在持久层中,具有将数据库操作抛出的原生异常翻译转化为spring的持久层异常的功能@Service
层是业务逻辑层注解,这个注解只是标注该类处于业务逻辑层。 用这些注解对应用进行分层之后,就能将请求处理,义务逻辑处理,数据库操作处理分离出来,为代码解耦,也方便了以后项目的维护和开发
@Controller和@Repository的区别
@Controller
@Controller
层是spring-mvc的注解,具有将请求进行转发,重定向的功能@Controller
注解类进行前端请求的处理,转发,重定向。包括调用Service层的方法@Service
注解类处理业务逻辑@Controller
层是spring-mvc的注解,具有将请求进行转发,重定向的功能
@Repository
-
@Repository
会被作为持久层操作(数据库)的bean来使用 -
@Repository
注解类作为DAO对象(数据访问对象,Data Access Objects),这些类可以直接对数据库进行操作 有这些分层操作的话,代码之间就实现了松耦合,代码之间的调用也清晰明朗,便于项目的管理假想一下,如果只用
@Controller
注解,那么所有的请求转发,业务处理,数据库操作代码都糅合在一个地方,那这样的代码该有多难拓展和维护
//\src\main\java\com\dao\CustomerDao.java
package com.dao;
import com.entity.Customer;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface CustomerDao {
Customer findCustomerById(Integer id);
List<Customer> findCustomerByName(String value);
int addCustomer(Customer customer);
int updateCustomer(Customer customer);
int deleteCustomer(Integer id);
}
6. 添加@MapperScan
- @MapperScan作用:指定要变成实现类的接口所在的包,然后包下面的所有接口在编译之后都会生成相应的实现类
- 添加位置:是在Springboot启动类上面添加
@MapperScan("com.dao")
//\src\main\java\com\Demo8Application.java
package com;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.dao")
public class Demo8Application {
public static void main(String[] args) {
SpringApplication.run(Demo8Application.class, args);
}
}
7. mapper
- Dao中的接口的方法对应于mapper中.xml中的SQL语句
- .xml 文件即 SQL 映射文件,该文件中配置了操作数据库的 SOL 语句
MyBatisX使用
自动转跳至mapper映射文件中并生成了以下代码
点击企鹅图片可以在dao和mapper之间转跳
参考资料:
<select>
<select>
中的信息是用于执行查询操作的配置
- id 属性:是
<select>
元素在映射文件中的唯一标识 - parameteType属性:用于指定传入参数的类型,这里表示传递给执行 SQL 的是一个 Integer
类型的参数 - esultType属性:用于指定返回结果的类型,这里表示返回的数据是 Customer 类型
//\src\main\resources\mapper\CustomerDao.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" >
<mapper namespace="com.dao.CustomerDao">
<select id="findCustomerById" parameterType="integer" resultType="com.entity.Customer">
select * from t_customer where id=#{id}
</select>
<select id="findCustomerByName" parameterType="string" resultType="com.entity.Customer">
select * from t_customer where username like '%${value}%'
</select>
<insert id="addCustomer" parameterType="com.entity.Customer">
INSERT INTO `t_customer`(`username`, `jobs`, `phone`) VALUES (#{username},#{jobs},#{phone});
</insert>
<update id="updateCustomer" parameterType="com.entity.Customer">
UPDATE `t_customer` SET `username` = #{username}, `jobs` = #{jobs}, `phone` = #{phone} WHERE `id` = #{id};
</update>
<delete id="deleteCustomer">
delete from `t_customer` where id=#{id}
</delete>
</mapper>
8. 测试类
package com;
import com.dao.CustomerDao;
import com.entity.Customer;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class Demo8ApplicationTests {
@Autowired
CustomerDao dao;
@Test
void test_find1() {
Customer customer = dao.findCustomerById(1);
System.out.println(customer);
}
@Test
void test_find2() {
List<Customer> customers = dao.findCustomerByName("j");
// customers.forEach(System.out::println);
for(Customer customer:customers){
System.out.println(customer);
}
}
@Test
void test_add() {
Customer customer = new Customer();
customer.setUsername("rose");
customer.setJobs("student");
customer.setPhone("13333533092");
int rows=dao.addCustomer(customer);
System.out.println(rows);
}
@Test
void test_update() {
Customer customer = dao.findCustomerById(4);
customer.setJobs("programer");
customer.setPhone("13311111111");
int rows=dao.updateCustomer(customer);
System.out.println(rows);
}
@Test
void test_delete() {
int rows=dao.deleteCustomer(4);
System.out.println(rows);
}
}
@Test
void test_update() {
Customer customer = dao.findCustomerById(4);
customer.setJobs("programer");
customer.setPhone("13311111111");
int rows=dao.updateCustomer(customer);
System.out.println(rows);
}
@Test
void test_delete() {
int rows=dao.deleteCustomer(4);
System.out.println(rows);
}
}