Java Web学习 MyBatis

1 概念

//一款优秀的持久层框架,用于简化 JDBC 开发
(1) 硬编码可以配置到配置文件
<1> 核心配置文件//替换连接信息,解决硬编码问题。
<2> SQL 映射文件//统一管理sql语句,解决硬编码问题。
(2) 操作繁琐的地方mybatis都自动完成
<1> 自动设置参数
<2> 自动封装结果集

 

2 Mybatis快速入门

(1) 创建数据表,添加数据

create database mybatis;
use mybatis;
drop table if exists tb_user;
create table tb_user(
id int primary key auto_increment,
username varchar(20),
password varchar(20),
gender char(1),
addr varchar(30)
);
INSERT INTO tb_user VALUES (1, '李明', '123', '男', '石家庄');
INSERT INTO tb_user VALUES (2, '丹尼', '456', '女', '美国');
INSERT INTO tb_user VALUES (3, '珍妮', '189', '男', '加拿大');

(2) 创建模块,导入坐标

//在创建好的模块中的 pom.xml 配置文件中添加依赖的坐标。

<dependencies>
	<!--mybatis依赖-->
	<dependency>
		<groupId>org.mybatis</groupId>
		<artifactId>mybatis</artifactId>
		<version>3.5.5</version>
	</dependency>
    <!--mysql 驱动-->
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>5.1.46</version>
	</dependency>
</dependencies>

(3) 编写 MyBatis 核心配置文件

//替换连接信息,解决硬编码问题。
//在模块下的 resources 目录下创建mybatis的配置文件 mybatis-config.xml

<?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>
	<typeAliases>
		<package name="com.itheima.pojo"/>
		<!--name属性的值是实体类所在包。-->
        <!--为com.itheima.pojo包下所有类设置别名,别名为类名。这样,sql映射文件中返回值就不必再写完整的路径。-->
	</typeAliases>
	<environments default="development">
        <!--environments:配置数据库连接环境信息。可以配置多个environment,通过default属性切换不同的environment。-->
		<environment id="development">
			<transactionManager type="JDBC"/>
			<dataSource type="POOLED">
                <!--数据库连接信息-->
				<property name="driver" value="com.mysql.jdbc.Driver"/>
				<property name="url" value="jdbc:mysql:///mybatis"/>
                <!--若运行时出现时区错误问题,则在url后面加上?serverTimezone=UTC,若出现不安全信息,在后面加上?useSSL=false。-->
                <!--若使用预编译则加上useServerPrepStmts=true-->
				<!--xml文件中不识别&,应使用转义字符&amp;。-->
				<property name="username" value="root"/>
				<property name="password" value="1234"/>
			</dataSource>
		</environment>
		<environment id="test">
			<transactionManager type="JDBC"/>
			<dataSource type="POOLED">
                <!--数据库连接信息-->
				<property name="driver" value="com.mysql.jdbc.Driver"/>
				<property name="url" value="jdbc:mysql:///mybatis"/>
				<property name="username" value="root"/>
				<property name="password" value="1234"/>
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<mapper resource="UserMapper.xml"/>
        <!--加载sql映射文件-->
	</mappers>
</configuration>

(4) 编写 SQL 映射文件

//统一管理sql语句,解决硬编码问题。
//在模块的 resources 目录下创建映射配置文件 UserMapper.xml(命名规则:数据表名+Mapper)

<?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="test">
	<!--名称空间,相当于包名。-->
	<select id="selectAll" resultType="com.itheima.pojo.User">
        <!--id:sql语句唯一标识符 resultType:sql返回值类型(必须要写全实体类路径,除非核心配置文件中有<typeAliases>标签进行了包扫描)。-->
        <!--编写到此处,便使用到pojo实体类,所以需要便编写pojo实体类。-->
		select * from tb_user;
	</select>
</mapper>

(5) 编码

<1> 在 com.itheima.pojo 包下创建 User类

public class User {
    private int id;
    private String username;
    private String password;
    private String gender;
    private String addr;
    //省略了 setter 和 getter 以及 toString 。
}

<2> 在 com.itheima 包下编写 MybatisDemo 测试类

public class MyBatisDemo {
	public static void main(String[] args) throws IOException {
		//1. 加载mybatis的核心配置文件,获取 SqlSessionFactory
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		//2. 获取SqlSession对象,用它来执行sql
		SqlSession sqlSession = sqlSessionFactory.openSession();
		//3. 执行sql
		List<User> users = sqlSession.selectList("test.selectAll"); //参数是一个字符串,该字符串必须是映射配置文件的namespace.id。
		//该步骤省略了手动封装查询结果,自动将查询结果封装,并打包成集合。
		//注意:此处user变量数据类型为List<User>,是一个list容器。
		System.out.println(users);
		//4. 释放资源
		sqlSession.close();
	}
}

 

3 初次Mapper代理开发

(1) 创建数据表,添加数据
(2) 创建模块,导入坐标
(3) 编写 MyBatis 核心配置文件
//如果Mapper接口名称和SQL映射文件名称相同,并在同一目录下,则可以使用包扫描的方式简化SQL映射文件的加载。

<mappers>
	<package name="com.itheima.mapper"/>
</mappers>

(4) 编写 SQL 映射文件

//先创建并编写映射文件,写好namespace,不编写statement,此时namespace爆红,之后根据namespace创建mapper接口。

在 resources 下创建 com/itheima/mapper 目录,并在该目录下创建 UserMapper.xml 映射配置文件
//注意该文件夹在resource下,是文件夹不是包,因此使用/而非.。
//编译完成后,java下的com.itheima.mapper包下的mapper接口会与resource下的com.itheima.mapper文件夹下的sql映射文件在同一文件夹内。

<mapper namespace="com.itheima.mapper.UserMapper">
    <!--Mapper代理开发要求1:设置SQL映射文件的namespace属性为Mapper接口全限定名。-->
    <!--该要求保证了Mapper接口映射到sql映射文件的正确位置。-->
    
</mapper>

(5) 在 com.itheima.mapper 包下创建 UserMapper接口

//注意:创建的是interface,不是class。

//Mapper代理开发要求2:定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和SQL映射文件放置在同一目录下。
//该要求保证了Mapper接口正确映射到sql映射文件。
public interface UserMapper {
	List<User> selectAll();
	//注意:此时返回值为list<User>,该方法只有方法签名。
	//Mapper代理开发要求3:在 Mapper 接口中定义方法,方法名就是SQL映射文件中sql语句的id,并保持参数类型和返回值类型一致。
	//该要求保证了Mapper接口中的方法正确映射到sql映射文件中的某一句sql语句。
}		

(6) 使用mybatis插件,点击接口,alt+enter 自动生成SQL映射文件中的Statement,并编写SQL语句。
//若出现实体类属性名和数据库表列名不一致,不能自动封装数据的问题,则使用resultMap,详情见 5。

<select id="selectAll" resultType="com.itheima.pojo.User">
    select * from tb_user;
</select>

(7) 编码
<1> 在 com.itheima.pojo 包下创建 User类
<2> 在 com.itheima 包下创建 MybatisDemo2 测试类
<2.1> 加载mybatis的核心配置文件,获取 SqlSessionFactory
<2.2> 获取SqlSession对象
<2.3> 获取UserMapper接口的代理对象,用它来执行sql
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
<2.4> 执行sql
List<User> users = userMapper.selectAll();
//通过UserMapper接口映射sql映射文件,通过接口方法映射sql语句。
System.out.println(users);
<2.5> 释放资源

 

4 二次Mapper代理开发

//与Mapper代理开发在同一个工程中,使用同一个核心配置文件。

(1) 创建数据表,添加数据

create table tb_brand
(
id int primary key auto_increment,
brand_name varchar(20),
company_name varchar(20),
ordered int,
description varchar(100),
status int
);
insert into tb_brand (brand_name, company_name, ordered, description, status)
values ('华为', '华为技术有限公司', 5, '构建万物互联的智能世界', 0),
('小米', '小米科技有限责任公司', 50, '为发烧而生', 1),
('OPPO', '广东欧珀移动通信有限公司', 100, '充电5分钟,通话两小时', 1);

(2) 在 com.itheima.pojo 包下创建 Brand 实体类。

public class Brand {
	// id 主键
	private Integer id;
	// 品牌名称
	private String brandName;
	// 企业名称
	private String companyName;
	// 排序字段
	private Integer ordered;
	// 描述信息
	private String description;
	// 状态:0:禁用 1:启用
	private Integer status;
	//省略了 setter 和 getter 以及 toString。自己写时要补全这部分代码。
}

(3) 编码

//测试代码需要在 test/java 目录下创建包及测试用例。

(3.1) 查询

<1> 查询所有记录

<1.1> 编写接口方法//参数:无,返回值:List<Brand> 

public interface BrandMapper {
	List<Brand> selectAll();
}

<1.2> 编写SQL语句

<mapper namespace="com.itheima.mapper.BrandMapper">
	<select id="selectAll" resultType="brand">
		select * from tb_brand;
	</select>
</mapper>

<1.3> 编写测试方法

List<Brand> brands = brandMapper.selectAll();
<2> 单条件查询

<2.1> 编写接口方法//参数:id,返回值:Brand

Brand selectById(int id);

<2.2> 编写SQL语句

<select id="selectById" resultMap="brandResultMap">
	select * from tb_brand where id = #{id};
	<!-- > < 等这些字符在xml中有特殊含义,所以此时我们需要将这些符号进行转义。例如,&lt; 就是 < 的转义字符。-->
</select>

<2.3> 编写测试方法

Brand brand = brandMapper.selectById(id);
<3> 多条件查询

//适用于所有多个参数的情况。
<3.1> 编写接口方法//参数:status、companyName、brandName,返回值:List<Brand>
List<Brand> selectByCondition(@Param("status") int status, @Param("companyName") String companyName,@Param("brandName") String brandName);
//该方式要求@Param("参数名称")与sql语句中#{参数名称}中参数名称相同。
List<Brand> selectByCondition(Brand brand);
//该方式要求在映射配置文件的SQL中使用 #{内容} 时,里面的内容必须和实体类属性名保持一致。
List<Brand> selectByCondition(Map map);
//该方式要求在映射配置文件的SQL中使用 #{内容}时,里面的内容必须和map集合中键的名称一致。
<3.2> 编写SQL语句

<select id="selectByCondition" resultMap="brandResultMap">
	select * from tb_brand where status = #{status}
	and company_name like #{companyName}
	and brand_name like #{brandName}
</select>

<3.3> 编写测试方法

① List<Brand> brands = brandMapper.selectByCondition(status, companyName, brandName);
② Brand brand = new Brand();
  brand.setStatus(status);
  brand.setCompanyName(companyName);
  brand.setBrandName(brandName);
  List<Brand> brands = brandMapper.selectByCondition(brand);
③ Map map = new HashMap();
  map.put("status" , status);
  map.put("companyName", companyName);
  map.put("brandName" , brandName);
  List<Brand> brands = brandMapper.selectByCondition(map);
<4> 多条件动态查询

<4.1> 编写接口方法//参数:status、companyName、brandName,返回值:List<Brand>
同多条件查询
<4.2> 编写SQL语句

<select id="selectByCondition" resultMap="brandResultMap">
	select * from tb_brand
	<where>
	<!--where 标签作用:
		替换where关键字
		会动态的去掉第一个条件前的and
		如果所有的参数没有值则不加where关键字-->
		<if test="status != null">
		    <!--if 标签表示条件判断-->
            <!--test 属性后跟逻辑表达式-->
			and status = #{status}
		</if>
		<if test="companyName != null and companyName != '' ">
			and company_name like #{companyName}
		</if>
		<if test="brandName != null and brandName != '' ">
			and brand_name like #{brandName}
		</if>
		<!--需要给每个条件前都加上and关键字。-->
	</where>
</select>

<4.3> 编写测试方法
同多条件查询

<5> 单条件动态查询

<5.1> 编写接口方法//参数:status、companyName、brandName,返回值:List<Brand>
同多条件查询
<5.2> 编写SQL语句

<select id="selectByConditionSingle" resultMap="brandResultMap">
	select * from tb_brand
	<where>
		<choose><!--相当于switch-->
			<when test="status != null"><!--相当于case-->
				status = #{status}
			</when>
			<when test="companyName != null and companyName != '' "><!--相当于case-->
				company_name like #{companyName}
                <!--模糊查询(即SQL语句中有like)的条件必须用正则表达式表示。-->
			</when>
			<when test="brandName != null and brandName != ''"><!--相当于case-->
				brand_name like #{brandName}
                <!--模糊查询(即SQL语句中有like)的条件必须用正则表达式表示。-->
			</when>
            <!--因为是单条件,所以每个条件前都不加and关键字。-->
		</choose>
	</where>
</select>

<5.3> 编写测试方法
同多条件查询

//模糊查询(即SQL语句中有like)的条件必须用正则表达式表示。
String brandName = brand.getBrandName();
    if (brandName != null && brandName.length() > 0) {
    brand.setBrandName("%" + brandName + "%");
    //表示中间时brandName的值即可。
}
String companyName = brand.getCompanyName();
    if (companyName != null && companyName.length() > 0) {
    brand.setCompanyName("%" + companyName + "%");
}

(3.2) 添加

//添加需手动提交事务。
//做添加操作时,id一般不需要修改。

<1> 添加记录

<1.1> 编写接口方法//参数:除id以外所有字段,返回值:无
void add(Brand brand);
int add(Brand brand);//返回值为该sql语句所影响的记录条数。
......
同多条件查询,有三种方式
<1.2> 编写SQL语句

<insert id="insert">
	insert into tb_brand (brand_name, company_name, ordered, description, status)
	values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
</insert>

<1.3> 编写测试方法

① SqlSession sqlSession = sqlSessionFactory.openSession(true);
  //设置自动提交事务,这种情况不需要手动提交事务了
  BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
  brandMapper.add(brand); 或 int count = brandMapper.add(brand);
② BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
  brandMapper.add(brand); 或 int count = brandMapper.add(brand);
  sqlSession.commit();
  //提交事务
<2> 主键返回

//在数据添加成功后,有时候需要获取插入数据库数据的主键(主键是自增长)。
//在 insert 标签上添加如下属性:
    //useGeneratedKeys:是够获取自动增长的主键值。true表示获取。
    //keyProperty :指定将获取到的主键值封装到哪个属性里。

<insert id="add" useGeneratedKeys="true" keyProperty="id">
	insert into tb_brand (brand_name, company_name, ordered, description, status)
	values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
</insert>
<!--在添加完数据后打印id属性值,能打印出来说明已经获取到了。-->

(3.3) 修改

//做修改操作时,要通过id查询到被修改的记录。
<1> 编写接口方法//参数:所有字段包括id,返回值:无
void update(Brand brand);
int update(Brand brand);//返回值为该sql语句所影响的记录条数。
//上述方法参数 Brand 就是封装了需要修改的数据,而id肯定是有数据的,这也是和添加方法的区别。
......
同多条件查询,有三种方式
<2> 编写SQL语句

<update id="update">
	update tb_brand
	<set>
	<!--set 标签可以用于动态包含需要更新的列,忽略其它不更新的列。-->
		<if test="brandName != null and brandName != ''">
			brand_name = #{brandName},
		</if>
		<if test="companyName != null and companyName != ''">
			company_name = #{companyName},
		</if>
		<if test="ordered != null">
			ordered = #{ordered},
		</if>
		<if test="description != null and description != ''">
			description = #{description},
		</if>
		<if test="status != null">
			status = #{status},
			<!--需要给每个条件后都加上,。-->
		</if>
	</set>
	where id = #{id};
</update>

<3> 编写测试方法

① SqlSession sqlSession = sqlSessionFactory.openSession(true);
  //设置自动提交事务,这种情况不需要手动提交事务了
  BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
  brandMapper.update(brand); 或 int count = brandMapper.update(brand);
② BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
  brandMapper.update(brand); 或 int count = brandMapper.update(brand);
  sqlSession.commit();
  //提交事务

(3.4) 删除

<1> 删除单条记录

<1.1> 编写接口方法
void deleteById(int id);
int deleteById(int id);
<1.2> 编写SQL语句

<delete id="deleteById">
	delete from tb_brand where id = #{id};
</delete>

<1.3> 编写测试方法

① SqlSession sqlSession = sqlSessionFactory.openSession(true);
  //设置自动提交事务,这种情况不需要手动提交事务了
  BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
  brandMapper.deleteById(brand); 或 int count = brandMapper.deleteById(brand);
② BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
  brandMapper.deleteById(brand); 或 int count = brandMapper.deleteById(brand);
  sqlSession.commit();
  //提交事务
<2> 删除多条记录

<2.1> 编写接口方法
void deleteByIds(int[] ids);
int deleteByIds(int[] ids); 
<2.2> 编写SQL语句

<delete id="deleteByIds">
	delete from tb_brand where id in
	<foreach collection="array" item="id" separator="," open="(" close=")">
	#{id}
	</foreach>
	;<!--经本人测试;似乎可以省略。-->
</delete>

/*  foreach 标签用来迭代任何可迭代的对象(如数组,集合)。
        collection 属性:
        mybatis会将数组参数,封装为一个Map集合。默认:array = 数组
        使用@Param注解改变map集合的默认key的名称
        item 属性:本次迭代获取到的元素。
        separator 属性:集合项迭代之间的分隔符。 foreach 标签不会错误地添加多余的分隔符。也就是最后一次迭代不会加分隔符。
        open 属性:该属性值是在拼接SQL语句之前拼接的语句,只会拼接一次。
        close 属性:该属性值是在拼接SQL语句拼接后拼接的语句,只会拼接一次。  */

<2.3> 编写测试方法

① SqlSession sqlSession = sqlSessionFactory.openSession(true);
  //设置自动提交事务,这种情况不需要手动提交事务了
  BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
  brandMapper.deleteByIds(brand); 或 int count = brandMapper.deleteByIds(brand);
② BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
  brandMapper.deleteByIds(brand); 或 int count = brandMapper.deleteByIds(brand);
  sqlSession.commit();
  //提交事务

 

5 注解实现CRUD

(1) 使用注解开发会比配置文件开发更加方便。如下就是使用注解进行开发

@Select(value = "select * from tb_user where id = #{id}")
public User select(int id);
//注解是用来替换映射配置文件方式配置的,所以使用了注解,就不需要再映射配置文件中书写对应的 statement

(2) Mybatis 针对 CURD 操作都提供了对应的注解,已经做到见名知意。如下:
<2.1> 查询 :@Select
<2.2> 添加 :@Insert
<2.3> 修改 :@Update
<2.4> 删除 :@Delete
(3) 注解完成简单功能,配置文件完成复杂功能。而我们之前写的动态 SQL 就是复杂的功能,如果用注解使用的话,就需要使用到 Mybatis 提供的SQL构建器来完成。

 

6 实体类属性名和数据库表列名不一致,不能自动封装数据的问题。

(1) 设置别名

<select id="selectAll" resultType="brand">
	select
	id, brand_name as brandName, company_name as companyName, ordered, description, status
	from tb_brand;
</select>

(2) SQL片段

<!--将需要复用的SQL片段抽取到sql标签中。-->
<sql id="brand_column">
	id, brand_name as brandName, company_name as companyName, ordered, description, status
</sql>
<!--在原sql语句中进行引用。-->
<select id="selectAll" resultType="brand">
	select
	<include refid="brand_column" />
    <!--使用include标签引用上述的SQL片段,而refid指定上述SQL片段的id值。-->
	from tb_brand;
</select>

(3) 使用resultMap

<resultMap id="brandResultMap" type="brand">
<!--id标签:完成主键字段的映射
		column属性:主键字段的字段名
		property属性:实体类的属性名
	result标签:完成一般字段的映射
		column属性:一般字段的字段名
		property属性:实体类的属性名-->
	<result column="brand_name" property="brandName"/>
	<result column="company_name" property="companyName"/>
	<!--在上面只需要定义字段名和属性名不一样的映射,而一样的则不需要专门定义出来。-->
</resultMap>
<select id="selectAll" resultMap="brandResultMap">
<!--注意:使用了resultMap,则会自动代替resultType。-->
	select * from tb_brand;
</select>

@Select(value = "select * from tb_brand")//若使用注解开发
@resultMap("brandResultMap")

 

7 Mybatis参数传递

(1) 单个参数

//所有封装为map集合的参数,都可以使用@Param注解替换map集合中默认的arg键名。
<1> POJO类型
直接使用。要求属性名和参数占位符名称 一致
<2> Map集合类型
直接使用。要求map集合的键名和参数占位符名称 一致
<3> Collection集合类型
Mybatis会将集合封装到map集合中,如下:
map.put("arg0",collection集合);
map.put("collection",collection集合;
<4> List集合类型
Mybatis会将集合封装到map集合中,如下:
map.put("arg0",list集合);
map.put("collection",list集合);
map.put("list",list集合);
<5> Array类型
Mybatis会将集合封装到map集合中,如下:
map.put("arg0",数组);
map.put("array",数组);
<6> 其他类型
直接使用。比如int类型,参数占位符名称任意。尽量做到见名知意。

(2) 多个参数

//我们在接口方法中定义多个参数,Mybatis 会将这些参数封装成Map集合对象,值就是参数值。
//若使用param注解,必须要求参数占位符中的值必须与map集合对象的的键值一致。
//若未使用param注解,也将参数占位符置为arg或param,则出错。
<1> 键在没有使用 @Param 注解时有以下命名规则:
<1.1> 以 arg 开头 :第一个参数就叫 arg0,第二个参数就叫 arg1,以此类推。如:
map.put("arg0",参数值1);
map.put("arg1",参数值2);
<1.2> 以 param 开头 : 第一个参数就叫 param1,第二个参数就叫 param2,依次类推。如:
map.put("param1",参数值1);
map.put("param2",参数值2);
<1.3> 代码验证

<select id="select" resultType="user">
	select * from tb_user where username=#{arg0} and password=#{arg1}
</select>
或者
<select id="select" resultType="user">
	select * from tb_user where username=#{param1} and password=#{param2}
</select>
<!--运行结果:正确-->

<2> 在接口方法参数上使用 @Param 注解,Mybatis会将arg开头的键名替换为对应注解的属性值。
//即map集合对象的键永远有两种,一种是param,任何情况下都适用;另一种是arg,仅在未使用param注解时可用,否则会被替代。
代码验证

User select(@Param("username") String username, String password);
<!--为第一个变量加上param注解。-->
<select id="select" resultType="user">
	select * from tb_user where username=#{arg0} and password=#{param2}
	<!--sql语句中第一个参数占位符继续使用arg0-->
</select>
<!--运行结果:错误-->

<3> 结论:以后接口参数是多个时,在每个参数上都使用 @Param 注解。这样代码的可读性更高。

 

8 mappper代理流程

实参传递到测试用例中的形参,若为多个参数或collection、array、list则封装为map对象传递,否则直接传递。
该形参所属方法对应的mapper接口接映射到对应的sql映射文件,将参数赋值给sql语句中对应的参数占位符。

 

9 SqlSessionFactory工具类抽取

(1) 在写Servlet的时候,因为需要使用Mybatis来完成数据库的操作,所以对于Mybatis的基础操作就出现了些重复代码,有了这些重复代码就会造成一些问题:
<1> 重复代码不利于后期的维护
<2> SqlSessionFactory工厂类进行重复创建
(2) 代码重复抽取工具类

public class SqlSessionFactoryUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        //静态代码块会随着类的加载而自动执行,且只执行一次
     try {
         String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        sqlSessionFactory = new
        SqlSessionFactoryBuilder().build(inputStream);
      } catch (IOException e) {
          e.printStackTrace();
      }
    }
    public static SqlSessionFactory getSqlSessionFactory(){
        return sqlSessionFactory;
    }
}

(3) 工具类抽取以后,以后在对Mybatis的SqlSession进行操作的时候,就可以直接使用
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
(4) SqlSession sqlSession = sqlSessionFactory.openSession();不能放入静态代码块。
//因为SqlSession代表的是数据库连接池,若放入代码块,只会执行一次,即多个用户使用一个数据库连接池。

posted @ 2023-03-12 17:42  10kcheung  阅读(66)  评论(0)    收藏  举报