项目前的知识回顾
创始人
2024-03-07 19:54:07
0

杂谈

什么是框架

应用方面:框架是整个或者部分系统的可重用设计

目的方面:框架是可被开发者定制的应用骨架

统一的舞台,不同人表演不同的节目

框架解决什么问题

框架主要解决技术整合的问题

MYBATIS

什么是Mybatis

Mybatis是一款半自动ORM持久层框架,具有较高的SQL灵活性,支持高级映射(一对一,多对多),动态SQL,延迟加载,缓存等

什么是ORM

对象关系映射(Object Relation Mapping)对象是指java对象,关系是指数据库中的关系模型,映射就是对象与关系模型之间的联系

解决的问题

  • 数据库频繁的创建链接,销毁内存,造成了资源浪费,使用数据库连接池可以解决这个问题
  • sql语句在代码中硬编码,sql变化可能较大,sql变化需要改变java代码
  • prepareStatement向占位符传参存在硬编码,where语句不一定,修改where需要修改java代码
  • 结果集存在硬编码,sql变化导致解析代码变化,系统不易维护

Mybatis与Hibernate的区别

Mybatis:

  • 入门简单,即学即用,提供了数据库查询的自动对象绑定功能

  • 可以进行更为细致的SQL优化,可以减少查询字段

  • 缺点就是框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改

  • 二级缓存机制不佳

Hibernate : 

  • 功能强大,数据库无关性好,对象关系(O/R)映射能力强

  • 有更好的二级缓存机制,可以使用第三方缓存

  • 缺点就是学习门槛不低,要精通门槛更高,而且怎么设计对象关系(O/R)映射,在性能和对象模型之间如何权衡取得平衡,以及怎样用好Hibernate方面需要你的经验和能力都很强才行

快速开发

引入项目依赖

	mysqlmysql-connector-java5.1.10org.mybatismybatis3.4.6org.projectlomboklombok1.18.12providedjunitjunit4.10test

创建配置文件 mybatis-config.xml




创建数据库配置文件

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/erp16?useUnicode=true&characterEncoding=UTF-8
username=root
password=root

创建对应数据库字段的实体类

package com.wzx.SSMOne.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {private Integer id;private String username;private String password;private String nickname;private Integer type;
}

创建接口书写方法

package com.wzx.MybatisOne.dao;import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;import java.util.List;public interface InterUserMapper {
//    @Select("select * from t_user where id = #{id}")/*@Select("select * from t_user where id = #{id}")User getById(int id);*/int add(User user);User getById(int id);List getList(@Param("username") String username);}

创建上面接口的映射文件   同名的mapper.xml



insert into t_user (username,password,nickname) values (#{username},#{password},#{nickname})

他俩的关系如图所示

 测试---使用sqlSession测试

import com.wzx.MybatisOne.dao.InterUserMapper;
import com.wzx.MybatisOne.dao.User;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.AfterAll;import java.io.IOException;
import java.io.InputStream;
import java.util.List;public class TestInter {SqlSession sqlSession;@Beforepublic void beforeSome() throws IOException {String resource = "mybatis-config.xml";//读取配置文件InputStream resourceAsStream = Resources.getResourceAsStream(resource);//获取session工厂SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);//获取sessionsqlSession = factory.openSession();}@Testpublic void insertSome(){User user = new User();user.setUsername("1234");user.setPassword("1234");user.setNickname("1234");user.setNickname("1234");User byId = sqlSession.getMapper(InterUserMapper.class).getById(2);System.out.println(byId);}@Testpublic void insertInterfaceSome(){User user = new User();user.setUsername("1234");user.setPassword("1234");user.setNickname("1234");user.setNickname("1234");sqlSession.getMapper(InterUserMapper.class).add(user);}@Testpublic void getByName(){List wzx = sqlSession.getMapper(InterUserMapper.class).getList("wzx");wzx.stream().forEach(System.out::println);}@Afterpublic void afterSome(){sqlSession.commit();}
}

 

总结:

  • 引入依赖,加载依赖
  • 编写全局配置文件,配置数据源
  • 编写对应数据库字段的实体类
  • 编写实现接口
  • 编写接口的映射文件---同名
  • 通过全局配置文件,创建SqlSessionFactory
  • 调用sqlSession上的一系列方法

各个子标签

一般将数据源的信息单独放在一个properties文件中,然后用这个标签引入,在下面environment标签中,就可以用${}占位符快速获取数据源的信息

用来开启或关闭mybatis的一些特性,比如可以用来开启延迟加载,可以用来开启二级缓存

给实体类起别名   resultType属性要写com.yogurt.po.Student,这太长了,所以可以用别名来简化书写

可以用来配置mybatis的插件,比如在开发中经常需要对查询结果进行分页,就需要用到pageHelper分页插件,这些插件就是通过这个标签进行配置的

用来配置数据源

用来配置mapper.xml映射文件,这些xml文件里都是SQL语句

mapper.xml的SQL语句中的占位符${}#{}

一般会采用#{},#{}在mybatis中,最后会被解析为?,其实就是Jdbc的PreparedStatement中的?占位符,它有预编译的过程,会对输入参数进行类型解析(如果入参是String类型,设置参数时会自动加上引号),可以防止SQL注入,如果parameterType属性指定的入参类型是简单类型的话(简单类型指的是8种java原始类型再加一个String),#{}中的变量名可以任意,如果入参类型是pojo,比如是Student类那么#{name}表示取入参对象Student中的name属性,#{age}表示取age属性,这个过程是通过反射来做的,这不同于${}${}取对象的属性使用的是OGNL(Object Graph Navigation Language)表达式

${},一般会用在模糊查询的情景,比如SELECT * FROM student WHERE name like '%${name}%';


Mapper三种开发形式

  • sqlSession执行对应语句,就是我们上面测试的那种

  • 使用注解(简单sql)

  • 利用接口代理(常用)

我们上面的快速入门就是使用的第一种sqlSession

使用接口代理

只需要在同目录写一个mapper接口和一个mapper映射文件即可

记住:

  1. mapper接口的全限定名,要和mapper.xml的namespace属性一致
  2. mapper接口中的方法名要和mapper.xml中的SQL标签的id一致
  3. mapper接口中的方法入参类型,要和mapper.xml中SQL语句的入参类型一致
  4. mapper接口中的方法出参类型,要和mapper.xml中SQL语句的返回值类型一致

效果如图
同名同级

其他不变,即可测试

效果如图

使用注解

直接在方法上,使用注解定义sql

此时还需在配置文件中定义一个映射,如下图

映射指定上图中的包名,意思是映射dao包下的所有接口

其他不变,效果如图

小case

主键返回

通常我们会将数据库表的主键id设为自增。在插入一条记录时,我们不设置其主键id,而让数据库自动生成该条记录的主键id,那么在插入一条记录后,如何得到数据库自动生成的这条记录的主键id呢?有两种方式

1.使用useGeneratedKeyskeyProperty属性

INSERT INTO student (name,score,age,gender) VALUES (#{name},#{score},#{age},#{gender});

2.使用子标签

INSERT INTO student (name,score,age,gender) VALUES (#{name},#{score},#{age},#{gender});SELECT LAST_INSERT_ID();

如果使用的是mysql这样的支持自增主键的数据库,可以简单的使用第一种方式;

测试代码如下

public class MapperProxyTest {private SqlSessionFactory sqlSessionFactory;@Beforepublic void init() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);}@Testpublic void test() {SqlSession sqlSession = sqlSessionFactory.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);Student student = new Student(-1, "Podman", 130, 15, 0);mapper.insert(student);sqlSession.commit();System.out.println(student.getId());}
}

批量处理

主要是动态SQL标签的使用,注意如果parameterTypeList的话,则在标签体内引用这个List,只能用变量名list,如果parameterType是数组,则只能用变量名array


	@Testpublic void testBatchQuery() {SqlSession sqlSession = sqlSessionFactory.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);List students = mapper.batchFind(Arrays.asList(1, 2, 3, 7, 9));students.forEach(System.out::println);}

结果

image-20200526210641300

 

resultMap

在声明返回值类型为实体类型之后,实体中的属性必须和查询语句中的属性对应上,但是我们在开发的过程中也难免会遇到无法对应的情况。比如说我们在进行数据库设计的时候,多个单词往往是用_连接,但是在实体类中的属性往往采用小驼峰的方式命名。这就导致字段名无法对应上,这个时候我们就需要配置resultMap来解决这个问题了


动态SQL

if



choose



where

标签只会在至少有一个子元素返回了SQL语句时,才会向SQL语句中添加WHERE,并且如果WHERE之后是以AND或OR开头,会自动将其删掉


foreach


set

 update t_usernickname = #{nickname},username = #{username},where id = #{id}

缓存

一级缓存

默认开启,同一个SqlSesion级别共享的缓存,在一个SqlSession的生命周期内,执行2次相同的SQL查询,则第二次SQL查询会直接取缓存的数据,而不走数据库,当然,若第一次和第二次相同的SQL查询之间,执行了DML(INSERT/UPDATE/DELETE),则一级缓存会被清空,第二次查询相同SQL仍然会走数据库
 

一级缓存在下面情况会被清除

  1. 在同一个SqlSession下执行增删改操作时(不必提交),会清除一级缓存
  2. SqlSession提交或关闭时(关闭时会自动提交),会清除一级缓存
  3. 对mapper.xml中的某个CRUD标签,设置属性flushCache=true,这样会导致该MappedStatement的一级缓存,二级缓存都失效(一个CRUD标签在mybatis中会被封装成一个MappedStatement)
  4. 在全局配置文件中设置 ,这样会使一级缓存失效,二级缓存不受影响
     

二级缓存

默认关闭,可通过全局配置文件中的开启二级缓存总开关,然后在某个具体的mapper.xml中增加,即开启了该mapper.xml的二级缓存。二级缓存是mapper级别的缓存,粒度比一级缓存大,多个SqlSession可以共享同一个mapper的二级缓存。注意开启二级缓存后,SqlSession需要提交,查询的数据才会被刷新到二级缓存当中

总结

  • 在使用二级缓存的时候,需要注意配置mybatis-config.xml中 开启二级缓存

  • 然后再mapper映射文件中使用cache标签标注开启,并对需要换成的语句添加useCache=”true”

  • 在mapper的映射文件中使用,代表当前mapper是开启二级缓存的

  • 在需要二级缓存的查询上增加useCache = true,代表当前查询是需要缓存的

  • 并且对应封装数据的实体类需要实现Serializable 接口

  • 对待缓存的数据,实现Serialization接口,代表这个数据是可序列化

  • 只有当sqlSession close之后,二级缓存才能生效

  • 当执行增删改操作的时候,必须执行commit()才能持久化到数据库中,同时二级缓存清空

  • session.clearCache()无法清除二级缓存,如果需要清除二级缓存,可以通过sqlSessionFactory.getConfiguration().getCache("缓存id").clear();

  • 但是当我们查询语句中,执行commit() 或者是close()关闭session,都不会清空二级缓存

关联查询

1-1

在实现1对1映射的时候,可以通过association属性进行设置。在这里有三种方式

1.使用select


2. 直接进行联查,在association中配置映射字段

    

autoMapping代表自动封装,如果不填写,则需要添加所有的对应关系。

这种方式的问题是,当association需要被多次引用的时候,就需要进行多次重复的配置,所以我们还有第三种方式,引用resultMap。 

3.嵌套的resultType

1-多

也是三种

 

       

延迟加载

延迟加载:

就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.

延迟加载是结合关联查询进行应用的。也就是说,只在 标签上起作用

好处:

先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。

坏处:

因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。

配置

 


事务

事务的隔离级别

  • 脏读
  • 幻读
  • 不可重复读

脏读 

脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问 这个数据,然后使用了这个数据。

不可重复读

是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。

幻读

是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。 同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象 发生了幻觉一样。

事务隔离

脏读

不可重复读

幻读

说明

Read uncommitted

直译就是"读未提交",意思就是即使一个更新语句没有提交,但是别 的事务可以读到这个改变.这是很不安全的。允许任务读取数据库中未提交的数据更改,也称为脏读。

Read committed

×

直译就是"读提交",可防止脏读,意思就是语句提交以后即执行了COMMIT以后,别的事务才能读到这个改变. 只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 

Repeatable read

×

×

直译就是"可以重复读",这是说在同一个事务里面先后执行同一个查询语句的时候,得到的结果是一样的.在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读。

Serializable

×

×

×

直译就是"序列化",意思是说这个事务执行的时候不允许别的事务并发执行. 完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞

分页

插件分页

1.添加依赖

com.github.pagehelperpagehelper5.1.6

2.配置文件配置

 

3.代码

	@Testpublic void test() {SqlSession sqlSession = sqlSessionFactory.openSession();ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);PageHelper.startPage(1,3);List products = mapper.selectByExample(new ProductExample());products.forEach(System.out::println);}

4.可以通过pageInfo获取分页的相关信息

@Test
public void test() {SqlSession sqlSession = factory.openSession();PageHelper.startPage(1,3);ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);List list = mapper.findAll();list.forEach(System.out::println);PageInfo pageInfo = new PageInfo<>(list);System.out.println(pageInfo.getTotal()); // 获得总数System.out.println(pageInfo.getPageSize());  // 获得总页数
}

这个pageInfo 里面有很多的属性

手动分页

配置同上

1.定义一个获取分页的实体类

package com.wzx.MybatisThree.dto;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageInfos {private int pageNums;private int start;private int pageSizes;public int getIndex(){return (this.pageNums - 1) * this.pageSizes;}
}

2.映射以及接口

3.测试

 @Testpublic void getUserSomePages(){PageInfos pageInfos = new PageInfos();pageInfos.setPageSizes(3);pageInfos.setPageNums(1);int index = pageInfos.getIndex();List userSomePages = sqlSession.getMapper(UserPage.class).getUserSomePages(index, pageInfos.getPageSizes());userSomePages.stream().forEach(System.out::println);}

获取前三条数据

 

 

相关内容

热门资讯

常用商务英语口语   商务英语是以适应职场生活的语言要求为目的,内容涉及到商务活动的方方面面。下面是小编收集的常用商务...
六年级上册英语第一单元练习题   一、根据要求写单词。  1.dry(反义词)__________________  2.writ...
复活节英文怎么说 复活节英文怎么说?复活节的英语翻译是什么?复活节:Easter;"Easter,anniversar...
2008年北京奥运会主题曲 2008年北京奥运会(第29届夏季奥林匹克运动会),2008年8月8日到2008年8月24日在中华人...
英语道歉信 英语道歉信15篇  在日常生活中,道歉信的使用频率越来越高,通过道歉信,我们可以更好地解释事情发生的...
六年级英语专题训练(连词成句... 六年级英语专题训练(连词成句30题)  1. have,playhouse,many,I,toy,i...
上班迟到情况说明英语   每个人都或多或少的迟到过那么几次,因为各种原因,可能生病,可能因为交通堵车,可能是因为天气冷,有...
小学英语教学论文 小学英语教学论文范文  引导语:英语教育一直都是每个家长所器重的,那么有关小学英语教学论文要怎么写呢...
英语口语学习必看的方法技巧 英语口语学习必看的方法技巧如何才能说流利的英语? 说外语时,我们主要应做到四件事:理解、回答、提问、...
四级英语作文选:Birth ... 四级英语作文范文选:Birth controlSince the Chinese Governmen...
金融专业英语面试自我介绍 金融专业英语面试自我介绍3篇  金融专业的学生面试时,面试官要求用英语做自我介绍该怎么说。下面是小编...
我的李老师走了四年级英语日记... 我的李老师走了四年级英语日记带翻译  我上了五个学期的小学却换了六任老师,李老师是带我们班最长的语文...
小学三年级英语日记带翻译捡玉... 小学三年级英语日记带翻译捡玉米  今天,我和妈妈去外婆家,外婆家有刚剥的`玉米棒上带有玉米籽,好大的...
七年级英语优秀教学设计 七年级英语优秀教学设计  作为一位兢兢业业的人民教师,常常要写一份优秀的教学设计,教学设计是把教学原...
我的英语老师作文 我的英语老师作文(通用21篇)  在日常生活或是工作学习中,大家都有写作文的经历,对作文很是熟悉吧,...
英语老师教学经验总结 英语老师教学经验总结(通用19篇)  总结是指社会团体、企业单位和个人对某一阶段的学习、工作或其完成...
初一英语暑假作业答案 初一英语暑假作业答案  英语练习一(基础训练)第一题1.D2.H3.E4.F5.I6.A7.J8.C...
大学生的英语演讲稿 大学生的英语演讲稿范文(精选10篇)  使用正确的写作思路书写演讲稿会更加事半功倍。在现实社会中,越...
VOA美国之音英语学习网址 VOA美国之音英语学习推荐网址 美国之音网站已经成为语言学习最重要的资源站点,在互联网上还有若干网站...
商务英语期末试卷 Part I Term Translation (20%)Section A: Translate ...