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文件中不识别&,应使用转义字符&。-->
<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接口的代理对象,用它来执行sqlUserMapper userMapper = sqlSession.getMapper(UserMapper.class);
<2.4> 执行sqlList<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中有特殊含义,所以此时我们需要将这些符号进行转义。例如,< 就是 < 的转义字符。-->
</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代表的是数据库连接池,若放入代码块,只会执行一次,即多个用户使用一个数据库连接池。

浙公网安备 33010602011771号