感谢你的路过,希望学生的笔记能给你一点微不足道的参考(2/100)
Java基础思维导图,完整Java体系的链接
目录标题
1、Mybatis概述
1.1 Mybatis概念
一个基于 Java 的持久层框架。包括 SQL Maps 和 Data Access Objects(DAO)。
Mybatis 基于java的持久层框架,它的内部封装了JDBC,让开发人员只需要关注SQL语句本身,不需要花费精力在驱动的加载、连接的创建、Statement的创建等复杂的过程。
Mybatis通过XML或注解的方式将要执行的各种的statement配置起来,并通过java对象和statement中的sql的动态参数进行映射生成最终执行的SQL语句,最后由mybatis框架执行SQL,并将结果直接映射为java对象。
采用了ORM思想解决了实体类和数据库表映射的问题。对JDBC进行了封装,屏蔽了JDBCAPI底层的访问细节,避免我们与jdbc的api打交道,就能完成对数据的持久化操作。
O–Object java对象
R- Relation 关系,就是数据库中的一张表
M-mapping 映射
1.2 JDBC编程
public class TestJDBC {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
String url="jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT";
//获取连接
conn= DriverManager.getConnection(url,"root","root");
//SQL语句
String sql="select * from team;";
ps=conn.prepareStatement(sql);
//执行查询
rs = ps.executeQuery();
//遍历结果集
List<Team> list=new ArrayList<>();
while (rs.next()){
Team team=new Team();
team.setTeamName(rs.getString("teamName"));
team.setTeamId(rs.getInt("teamId"));
team.setCreateTime(rs.getDate("createTime"));
team.setLocation(rs.getString("location"));
list.add(team);
}
list.forEach(team -> System.out.println(team));
}catch (Exception e){
e.printStackTrace();
}finally {
try {
//关闭资源
if (rs != null){
rs.close();
}
if (ps != null){
ps.close();
}
if (conn != null){
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
1.3 Mybatis解决的问题
1、数据库连接的创建、释放连接的频繁操作造成资源的浪费从而影响系统的性能。
2、SQL语句编写在代码中,硬编码造成代码不容易维护,实际应用中SQL语句变化的可能性比较大,一旦变动就需要改变java类。
3、使用preparedStatement的时候传递参数使用占位符,也存在硬编码,因为SQL语句变化,必须修改源码。
4、对结果集的解析中也存在硬编码。
2、Mybatis入门案例
2.1 创建数据库和表
CREATE TABLE `team` (
`teamId` int NOT NULL AUTO_INCREMENT COMMENT '球队ID',
`teamName` varchar(50) DEFAULT NULL COMMENT '球队名称',
`location` varchar(50) DEFAULT NULL COMMENT '球队位置',
`createTime` date DEFAULT NULL COMMENT '球队建立时间',
PRIMARY KEY (`teamId`)
) ENGINE=InnoDB AUTO_INCREMENT=1003 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
2.2 创建maven项目,添加Mybatis的jar依赖
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
2.3 编写Mybatis的配置文件
一般情况下:配置文件的名称可以自定义,课程中使用mybatis.xml。配置文件放置在java/resources中。头文件去官网中复制粘贴。在这里给大家提供一个中文的网站。Mybatis网址
<?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>
<!--配置 mybatis 环境-->
<environments default="development">
<!--id:数据源的名称-->
<environment id="development">
<!--事务类型:使用 JDBC 事务,使用 Connection 的提交和回滚-->
<transactionManager type="JDBC"></transactionManager>
<!--数据源 dataSource:创建数据库 Connection 对象
type: POOLED 使用数据库的连接池
-->
<dataSource type="POOLED">
<!--连接数据库的四大参数
注意数据库版本使用的是MySQL8,如果是mysql5的话,driver和url都不一样,参考学过的JDBC-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?
useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
</configuration>
2.4 编写实体类
实体类中的属性必须与表中的列名保持一致
package com.kkb.pojo;
import java.util.Date;
/**
* ClassName: Team
* 球队的实体类
* @author wanglina
* @version 1.0
*/
public class Team {
private Integer teamId;
private String teamName;
private String location;
private Date createTime;
@Override
public String toString() {
return "Team{" +
"teamId=" + teamId +
", teamName='" + teamName + '\'' +
", location='" + location + '\'' +
", createTime=" + createTime +
'}';
}
//省略set get方法
}
2.5 编写ORM映射文件
我们是针对实体类Team.java和表Team进行ORM映射.Mybatis框架中,ORM映射是针对SQL语句进行,Mybatis框架将SQL语句抽取到了XML中。所以我们需要针对每个实体类编写XML映射文件。
2.5.1 XML映射文件必须与实体类在同一个包下面
2.5.2 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="com.kkb.pojo.Team">
<!-- id="自定义名称,id不能重复;相当于dao中的方法名称"
resultType="使用的要求:实体类中的属性名与表中的列名一致"
-->
<select id="queryAll" resultType="com.kkb.pojo.Team">
select * from team;
</select>
</mapper>
2.6 将映射文件注册到mybatis的配置文件中
<?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">
......
</environment>
</environments>
<!-- 注册映射文件 -->
<mappers>
<mapper resource="com/kkb/pojo/Team.xml"/>
</mappers>
</configuration>
2.7 配置映射文件的扫描位置
pom.xml文件配置映射文件的扫描路径
<build>
<resources>
<resource>
<directory>src/main/java</directory><!--所在的目录-->
<includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
//省略
</plugins>
</build>
2.8 使用Mybatis框架的核心接口测试
package com.kkb.test;
import com.kkb.pojo.Team;
import com.mysql.cj.Session;
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.Test;
import java.io.IOException;
import java.io.Reader;
import java.util.List;
/**
* ClassName: TeamTest
* Team 测试类
* @author wanglina
* @version 1.0
*/
public class TeamTest {
//mybatis的配置文件--相当于创建工厂的图纸
private String resource="mybatis.xml";
@Test
public void testFindAll(){
try {
//1、读取mybatis的配置文件
Reader reader = Resources.getResourceAsReader(resource) ;
//2、创建SqlSessionFactory对象,目的是获取sqlSession--根据图纸创建工厂
SqlSessionFactory sqlSessionFactory= new SqlSessionFactoryBuilder().build(reader);
//3、创建可以执行SQL语句的SqlSession--工厂创建产品
SqlSession sqlSession = sqlSessionFactory.openSession();
//4、执行SQL语句
List<Team> teamList = sqlSession.selectList("com.kkb.pojo.Team.findAll");
//5、循环输出查询的结果
for (Team team : teamList) {
System.out.println(team);
}
//6、关闭SqlSession,释放资源
sqlSession.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.9入门案例的增删改查
2.9.1 根据ID查询单个对象
Team.xml的映射文件中添加:
<!--
根据ID查询
parameterType="参数的类型",目前只支持一个参数
where teamId=#{id}: #{id}表示参数 id-自定义,只需要符合命名规范即可,没有实际对应意义
-->
<select id="findById" parameterType="int" resultType="com.kkb.pojo.Team">
select * from team where teamId=#{id}
</select>
测试类中添加如下内容:
private SqlSession sqlSession;
@Test
public void testFindById(){
Team team=sqlSession.selectOne("com.kkb.pojo.Team.queryById",1001);
System.out.println(team);
}
@Before
public void before() throws IOException {
//1、读取mybatis的配置文件
Reader reader = Resources.getResourceAsReader(resource) ;
//2、创建SqlSessionFactory对象,目的是获取sqlSession--根据图纸创建工厂
SqlSessionFactory sqlSessionFactory= new SqlSessionFactoryBuilder().build(reader);
//3、创建可以执行SQL语句的SqlSession--工厂创建产品
sqlSession = sqlSessionFactory.openSession();
}
@After
public void after(){
sqlSession.close();
}
2.9.2 增删改
Team.xml的映射文件中添加:
<!--删除一个球队 -->
<delete id="del" >
delete from team where teamId=#{id}
</delete>
<!--更新一个球队 -->
<update id="update" parameterType="com.kkb.pojo.Team">
update team set teamName=#{teamName},location=#{location}
where teamId=#{teamId}
</update>
<!--添加一个球队
parameterType="com.kkb.pojo.Team" 将对象作为参数,
#{值} 值必须是实体类中的属性名称,其实就是占位符?
-->
<insert id="add" parameterType="com.kkb.pojo.Team" >
INSERT INTO `team` (`teamName`, `location`, `createTime`)
VALUES (#{teamName}, #{location}, #{createTime})
</insert>
测试类中添加如下方法:
@Test
public void testDel(){
int num = sqlSession.delete("com.kkb.pojo.Team.del", 1049);
sqlSession.commit();
System.out.println(num);
}
@Test
public void testUpdate(){
Team team=sqlSession.selectOne("com.kkb.pojo.Team.queryById",1049);
team.setTeamName("linawang的球队");
team.setLocation("洛杉矶");
int num = sqlSession.update("com.kkb.pojo.Team.update", team);
sqlSession.commit();
System.out.println(num);
}
@Test
public void testAdd(){
Team team=new Team();
team.setTeamName("lina的球队");
team.setLocation("北京");
team.setCreateTime(new Date());
int num = sqlSession.insert("com.kkb.pojo.Team.add", team);//增删改必须手动提交事务
sqlSession.commit();//手动提交事务
System.out.println(num);
}
3、Mybatis对象分析
3.1 Resources
Resources 类,顾名思义就是资源,用于读取资源文件。其有很多方法通过加载并解析资源文件,返回不同类型的 IO 流对象。
3.2 SqlSessionFactoryBuilder
SqlSessionFactory 的 创 建 , 需 要 使 用 SqlSessionFactoryBuilder 对 象 的 build() 方 法 。 事实上使用SqlSessionFactoryBuilder的原因是将SqlSessionFactory这个复杂对象的创建交由Builder来执行,也就是使用了建造者设计模式。
建造者模式: 又称生成器模式,是一种对象的创建模式。 可以将一个产品的内部表象与产品的生成过程分割开来, 从而可以使一个建造过程生成具有不同的内部表象的产品(将一个复杂对象的构建与它的表示分离, 使得同样的构建过程可以创建不同的表示). 这样用户只需指定需要建造的类型就可以得到具体产品,而不需要了解具体的建造过程和细节.
在建造者模式中,角色分指导者(Director)与建造者(Builder): 用户联系指导者, 指导者指挥建造者, 最后得到产品. 建造者模式可以强制实行一种分步骤进行的建造过程.
3.3 SqlSessionFactory
SqlSessionFactory 接口对象是一个重量级对象(系统开销大的对象),是线程安全的,所以一个应用只需要一个该对象即可。创建SqlSession 需要使用 SqlSessionFactory 接口的的 openSession()方法。
默认的 openSession()方法没有参数,它会创建有如下特性的 SqlSession:
1、会开启一个事务(也就是不自动提交)。
2、将从由当前环境配置的 DataSource 实例中获取 Connection 对象。事务隔离级别将会使用驱动或数据源的默认设置。
3、预处理语句不会被复用,也不会批量处理更新。
openSession(true):创建一个有自动提交功能的 SqlSession
openSession(false):创建一个非自动提交功能的 SqlSession,需手动提交
openSession():同 openSession(false)
3.4 SqlSession
SqlSession 接口对象用于执行持久化操作。一个 SqlSession 对应着一次数据库会话,一次会话以SqlSession 对象的创建开始,以SqlSession 对象的关闭结束。
SqlSession 接口对象是线程不安全的,所以每次数据库会话结束前,需要马上调用其 close()方法,将其关闭。再次需要会话,再次创建。SqlSession 在方法内部创建,使用完毕后关闭。
SqlSession 类中有超过 20 个方法,我们常用的几乎都是执行语法相关的方法。
这些方法被用来执行定义在 SQL 映射的 XML 文件中的 SELECT、INSERT、UPDATE 和 DELETE 语句。它们都会自行解释,每一句都使用语句的 ID 属性和参数对象,参数可以是原生类型(自动装箱或包装类)、JavaBean、POJO 或 Map。
<T> T selectOne(String statement, Object parameter)
<E> List<E> selectList(String statement, Object parameter)
<K,V> Map<K,V> selectMap(String statement, Object parameter, String mapKey)
int insert(String statement, Object parameter)
int update(String statement, Object parameter)
int delete(String statement, Object parameter)
<!--
selectOne 和 selectList 的不同仅仅是 selectOne 必须返回一个对象或 null 值。如果返回值多于一个,那么就会抛出异常。
selectMap 稍微特殊一点,因为它会将返回的对象的其中一个属性作为 key 值,将对象作为 value 值,从而将多结果集转为 Map 类型值。因为
并不是所有语句都需要参数,所以这些方法都重载成不需要参数的形式。
-->
3.5 Mybatis架构
1、Mybatis.xml文件是mybatis框架的全局配置文件,配置了mybatis框架运行的环境等信息。Mapper1.xml…是SQL的映射文件,文件中配置了所有的操作数据库的sql语句,这些文件需要在全局配置文件中加载。
2、通过mybatis环境等配置信息构建SqlSessionFactroy ,相当于是产生连接池
3、由会话工厂创建SqlSession即会话(连接),操作数据库需要通过SqlSession进行的。
4、Mybatis底层自定义了Executor执行器的接口操作数据库,Executor接口有两个实现,一个基本的执行器,一个是缓存的执行器。
5、Mapped statement 也是mybatis框架一个底层的封装对象,他包装了mybatis配置信息以及sql映射信息。Mapper.xml文件中的一个SQL语
句对应一个Mapped statement对象,sql的id就是Mapped statement的id。
6、Mapped statement对SQL执行输入参数的定义,输入参数包括HashMap、基本类型、pojo,Executor通过Mapped statemen在执行SQL语句前将输入java对象映射到sql语句中,执行完毕SQL之后,输出映射就是JDBC编码中的对preparedStatement 执行结果的定义。
4、配置日志文件
4.1 添加jar依赖
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
4.2 添加日志配置文件
在resource下添加log4j.properties配置文件
#Global logging configuration info warning error
log4j.rootLogger=DEBUG,stdout
#Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
4.3 在mybatis配置文件中添加日志的配置
<configuration>
<!--配置日志,注意顺序:查看属性点击configuration进入查看即可-->
<settings>
<setting name="logImpl" value="LOG4J" />
</settings>
......
4.4 结果
5、使用原有的Dao方式开发
5.1 创建工具类
5.1.1 ThreadLocal
ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是threadlocalvariable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。
示例:
class Test{
private ThreadLocal<String> str = new ThreadLocal<String>();
private List<String> list = new ArrayList<String>();
class A extends Thread {
public void run() {
str.set("wanglina");
System.out.println("A...." + str.get());
list.add("AAA");
System.out.println("A<<<"+list.get(0));
}}
class B extends Thread {
public void run() {
System.out.println("B...." + str.</