🧸安清h:个人主页
🎥个人专栏:【计算机网络】,【Mybatis篇】
🚦作者简介:一个有趣爱睡觉的intp,期待和更多人分享自己所学知识的真诚大学生。
目录
🎯一.关联映射概述
🚦简述
关联映射是数据处理和编程中的一个重要概念,尤其在数据库和面向对象编程中应用广泛。它主要处理实体之间的关系,无论是将这种关系映射到数据库表之间,还是在面向对象编程中处理类之间的关系。实体通常指的是具体的事物,如用户、订单、产品等,在数据库中通常表示为表,而表中的每一行代表一个实体。
关联映射的核心在于处理实体之间的关系,这种关系可以是简单的对应关系,也可以是更复杂的如一对一、一对多或多对多的关系。例如,一个用户可以有多个订单,但一个订单只属于一个用户,这就是典型的一对多关系。在数据库中,这种关系需要通过外键来建立连接,确保数据的完整性和准确性。
在面向对象编程中,关联映射则处理类之间的关系。类是对象的模板或蓝图,定义了对象的属性和行为。当两个类需要建立关联关系时,通常通过属性引用来实现。这种关联是有方向性的,也就是说,一个类可能引用另一个类的实例,但不一定被另一个类的实例所引用。
🚦三种Java对象关联映射关系
1.一对一(1:1)关联映射:
- 在这种关系中,一个对象与另一个对象有且仅有一个关联。
- 例如,一个用户(User)对象可能与一个个人资料(Profile)对象关联,每个用户只有一个个人资料,每个个人资料也只属于一个用户。
- 在数据库中,这通常通过在两个表之间共享一个主键或者使用外键来实现。
- 在Java类中,可以通过在一个类中定义另一个类的实例作为私有成员来表示。
2.一对多(1:N)关联映射:
- 这种关系表示一个对象可以与多个对象关联,而每个对象只能与一个对象关联。
- 例如,一个部门(Department)对象可以有多个员工(Employee)对象,但每个员工只能属于一个部门。
- 在数据库中,通常是通过在“多”的一方的表中包含“一”的一方的表的主键作为外键来实现的。
- 在Java类中,这通常是通过在“一”的一方的类中定义一个集合(如List或Set)来表示,而在“多”的一方的类中定义一个指向“一”的一方的引用。
3.多对多(M:N)关联映射:
- 在这种关系中,两个对象可以相互关联多个对象。
- 例如,学生(Student)和课程(Course)之间的关系,一个学生可以选多个课程,一个课程也可以被多个学生选择。
- 在数据库中,这通常需要一个中间表(或称为连接表),该表包含两个关联表的主键。
- 在Java类中,这通常是通过在两个类中各自定义一个集合来表示,每个集合包含对方类的实例。
Java对象描述数据之间的关系示意图如下:
🎯二.多对多查询
🚦数据表准备
在数据库mybatis中创建三个表,分别为product产品表,ordersitem关联表,orders订单表,并向三个表中插入数据,具体代码如下:
#创建orders表
create table orders(
id int primary key auto_increment,
number varchar(50) not null ,
user_id int not null,
foreign key (user_id ) references user(id)
);
#插入数据
insert into orders values (1,'10001',1);
insert into orders values (2,'10002',2);
insert into orders values (3,'10003',3);
#创建product表
create table product(
id int primary key auto_increment,
name varchar(100),
price DOUBLE
);
#插入数据
insert into product values (1,'红楼梦',59);
insert into product values (2,'三国演义',53);
insert into product values (3,'水浒传',62);
#创建ordersitem表
create table ordersitem(
id int primary key auto_increment,
orders_id int,
product_id int,
foreign key (orders_id) references orders(id),
foreign key (product_id) references product(id)
);
#插入数据
insert into ordersitem values (1,1,1);
insert into ordersitem values (2,1,3);
insert into ordersitem values (3,3,3);
🚦POJO类准备
在包com.haust.pojo中创建类Product和类Orders,在类Product中会有一个私有成员变量productList,它的类型是List<Orders>,意味着 productList
是一个可以存储多个 Product
对象的列表。类Orders同样如此。
类Product具体代码如下:
public class Product {
private int id;
private String name;
private Double price;
private List<Orders> orders;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public List<Orders> getOrders() {
return orders;
}
public void setOrders(List<Orders> orders) {
this.orders = orders;
}
@Override
public String toString() {
return "Product{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
", orders=" + orders +
'}';
}
}
类Orders具体代码如下:
public class Orders {
private Integer id;
private String number;
private List<Product> productList;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public List<Product> getProductList() {
return productList;
}
public void setProductList(List<Product> productList) {
this.productList = productList;
}
@Override
public String toString() {
return "Orders{" +
"id=" + id +
", number='" + number + '\'' +
", productList=" + productList +
'}';
}
}
🚦映射文件
在resources中的mapper包中创建两个映射文件,分别是ProductMapper.xml和OrdersMapper.xml。
OrdersMapper.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.haust.mapper.OrdersMapper">
<select id="findOrdersWithProduct" parameterType="Integer"
resultMap="OrdersWithProductResult">
select * from orders where id=#{id}
</select>
<resultMap id="OrdersWithProductResult" type="com.haust.pojo.Orders">
<id property="id" column="id"/>
<result property="number" column="number"/>
<collection property="productList" column="id" ofType="com.haust.pojo.Product"
select="com.haust.mapper.ProductMapper.findProductById">
</collection>
</resultMap>
</mapper>
ProductMapper.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.haust.mapper.ProductMapper">
<select id="findProductById" parameterType="Integer" resultType="com.haust.pojo.Product">
select * from product where id in(
select product_id from ordersitem where orders_id=#{id}
)
</select>
</mapper>
🚦核心配置文件
在mybatis-config.xml文件中添加如下代码:
<mappers>
<mapper resource="mapper/OrdersMapper.xml"/>
<mapper resource="mapper/ProductMapper.xml"/>
</mappers>
🚦创建接口类
在com.haust.mapper包中分别创建接口类ProductMapper和OrdersMapper。
ProductMapper具体代码如下:
public interface ProductMapper {
List<Product> findProductById(Product product);
}
OrdersMapper具体代码如下:
public interface OrdersMapper {
List<Orders> findOrdersWithProduct(Orders orders);
}
🚦创建Util类
在com.haust.util包中创建类MybatisUtil,具体代码如下:
public class MybatisUtil {
private static SqlSessionFactory sqlSessionFactory=null;
static {
try {
Reader reader= Resources.getResourceAsReader("mybatis-config.xml");
sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static SqlSession getSession(){
return sqlSessionFactory.openSession();
}
}
🚦创建测试类
最后在包com.haust.test中创建测试类MybatisTest,并在其中编写测试方法testFindById,具体代码如下:
@Test
public void testFindById(){
SqlSession sqlSession=MybatisUtil.getSession();
OrdersMapper ordersMapper=sqlSession.getMapper(OrdersMapper.class);
Orders orders=new Orders();
orders.setId(1);
List<Orders> list=ordersMapper.findOrdersWithProduct(orders);
for(Orders o:list){
System.out.println(o);
}
sqlSession.close();
}
🎯Mybatis缓存机制
🚦简述
MyBatis的缓存机制包括一级缓存和二级缓存。
一级缓存(Local Cache)是基于
SqlSession
的,它默认是开启的,并且不能关闭。一级缓存的作用域是同一个SqlSession
,在同一个SqlSession
中两次执行相同的sql语句,第一次执行完毕会将数据库查询的数据写到缓存(内存),第二次会从缓存中获取数据而不进行数据库查询,从而提高了查询效率。一级缓存的生命周期很短,当SqlSession
调用close()
方法时,一级缓存将不可用。如果SqlSession
调用了clearCache()
方法,会清空一级缓存中的数据,但是SqlSession
对象还可以使用。此外,SqlSession
中执行了任何一个update
(修改)、delete
(删除)、insert
(新增)操作后,一级缓存也会被清空。二级缓存(Global Cache)是跨
SqlSession
的,它的作用域是mapper的同一个namespace,不同的sqlSession
两次执行相同namespace下的sql语句且向sql中传递的参数也相同时,第一次执行完毕会将数据库中查询到的数据写到缓存(内存),第二次会直接从缓存中获取,从而提高了查询效率。二级缓存需要手动配置开启,配置文件中使用<cache>
元素进行配置,并在需要使用二级缓存的映射文件中添加<cache-ref>
元素引用全局的缓存。二级缓存可以配置多种参数,如缓存回收策略、刷新间隔、引用数目、只读等。二级缓存默认是不开启的,需要在MyBatis配置文件中设置开启。
🚦一级缓存
在数据表中多次查询同一信息,第一次查询时,程序会将查询结果写入Mybatis一级缓存,在第二次查询时,Mybatis直接从一级缓存中读取,不再访问数据库进行查询。在执行增删改任意操作时,Mybatis会清空缓存中的内容以防止程序误读。
✨数据表准备
create table book(
id int primary key auto_increment,
bookName varchar(100),
price DOUBLE,
author varchar(100)
);
insert into book values (1,'红楼梦',57,'曹雪芹');
insert into book values (2,'西游记',48,'吴承恩');
insert into book values (3,'三国演义',67,'罗贯中');
✨POJO类准备
public class Book implements Serializable {
private Integer id;
private String bookName;
private Double price;
private String author;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public String toString() {
return "Book{" +
"id=" + id +
", bookName='" + bookName + '\'' +
", price=" + price +
", author='" + author + '\'' +
'}';
}
}
✨映射文件
<?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.haust.mapper.BookMapper">
<select id="findBookById" parameterType="Integer" resultType="com.haust.pojo.Book">
select * from book where id=#{id}
</select>
</mapper>
✨创建接口类
public interface BookMapper {
List<Book> findBookById(Book book);
}
✨创建log4j.properties文件
#全局日志配置
log4j.rootLogger=DEBUG,Console
#控制台输出配置
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
#日志输出级别
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
✨创建测试类
@Test
public void testFindBook(){
SqlSession sqlSession= MybatisUtil.getSession();
BookMapper bookMapper=sqlSession.getMapper(BookMapper.class);
Book book=new Book();
book.setId(1);
List<Book> list=bookMapper.findBookById(book);
for(Book b:list){
System.out.println(b);
}
Book book2=new Book();
book2.setId(1);
List<Book> list2=bookMapper.findBookById(book);
for(Book b2:list2){
System.out.println(b2);
}
sqlSession.close();
}
🚦二级缓存
任意的增删改会导致二级缓存失效,二级缓存需要手动开启,首先是需要在mybatis-config.xml中通过<settings>元素开启二级缓存全局配置:
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
其次是 通过Mybatis映射文件中的<cache>元素来完成,载<mapper>元素下添加如下代码:
<cache></cache>
为了验证上述配置,在测试类中添加测试方法testFindById2,具体代码如下:
@Test
public void testFindById2(){
SqlSession sqlSession1=MybatisUtil.getSession();
SqlSession sqlSession2=MybatisUtil.getSession();
Book book1=sqlSession1.selectOne("com.haust.mapper.BookMapper.findBookById",1);
System.out.println(book1.toString());
sqlSession1.close();
Book book2=sqlSession2.selectOne("com.haust.mapper.BookMapper.findBookById",1);
System.out.println(book2.toString());
sqlSession1.close();
}
以上就是今天要讲的内容了,到此为止,Mybatis关联映射部分已经更完,如果您对我的文章感兴趣的话,可以订阅我的专栏【Mybatis篇】,在接下来的文章中会写到Mybatis的注解开发,非常感谢您的阅读,如果这篇文章对您有帮助,那将是我的荣幸。我们下期再见啦🧸!