package com.qf.java2107.test;
import org.junit.Test;
import java.math.BigDecimal;
import java.sql.*;
/**
* @author ghy
* @version 1.0
* @date 2021-12-22
**/
public class JdbcTest {
/**
* 存在的问题:
* 1. 需要频繁的手动获取连接
* 2. 需要手动封装查询结果集
* 3. 需要手动释放资源
* 4. SQL硬编码
* 有自己封装的工具类,也有DBUtils等工具类API。但是都没有从根本上解决上面的问题
*/
@Test
public void testJdbc(){
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
//1.反射加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取数据库连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/java2106_hotel", "root", "root");
//3.编写SQL
String sql = "SELECT * FROM t_user WHERE user_id = ?";
//4.获取执行SQL的载体对象,预编译SQL
preparedStatement = connection.prepareStatement(sql);
//填充占位符
preparedStatement.setLong(1, 3);
//5.执行SQL
resultSet = preparedStatement.executeQuery();
//6.处理结果
if (resultSet.next()) {
//user_id : 结果集的列名
long userId = resultSet.getLong("user_id");
String username = resultSet.getString("username");
BigDecimal balance = resultSet.getBigDecimal("balance");
System.out.println(userId + "," + username + "," + balance );
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
//7.释放资源
//先开后关
try {
if(null != resultSet) {
resultSet.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(null != preparedStatement) {
preparedStatement.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(null != connection) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
存在的问题
通过ORM框架解决JDBC存在的问题
Object Relation Mapping:对象关系映射
Java对象 | 数据库表 |
---|---|
类名 | 表名 |
属性名 | 列名【字段名】 |
对象 | 行【记录】 |
概述:就是一个半成品软件
需要使用框架帮我们完成JavaEE应用的开发
作用
能够帮我们快速有效的开发JavaEE应用
有自己对应用场景的完整解决方案
是一款开源的、优秀的、支持定制SQL的ORM框架
官网:mybatis – MyBatis 3 | 简介
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
参考官网案例
创建数据库表
导入依赖
实体类
Mapper接口【Dao接口】
SQL映射文件
全局配置文件
测试
创建数据库表
CREATE TABLE `t_user` (
`user_id` bigint(100) NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` varchar(20) DEFAULT NULL COMMENT '用户名',
`password` varchar(32) DEFAULT NULL COMMENT '密码',
`nick_name` varchar(20) DEFAULT NULL COMMENT '昵称',
`is_admin` tinyint(4) DEFAULT NULL COMMENT '是否管理员 0:否 1:是',
`phone` varchar(11) DEFAULT NULL COMMENT '手机',
`gender` tinyint(4) DEFAULT NULL COMMENT '性别 0:保密 1:男 2:女',
`birth` date DEFAULT NULL COMMENT '生日',
`user_status` tinyint(4) DEFAULT NULL COMMENT '状态(是否激活) 0:否 1:是',
`user_create_time` datetime DEFAULT NULL COMMENT '创建时间',
`user_update_time` datetime DEFAULT NULL COMMENT '更新时间',
`is_delete` tinyint(4) DEFAULT NULL COMMENT '是否删除 0:否 1:是',
`is_member` tinyint(4) DEFAULT NULL COMMENT '是否会员 0:否 1:是',
`balance` decimal(20,2) DEFAULT NULL COMMENT '账户余额',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COMMENT='这是一个用户表';
insert into `t_user`(`user_id`,`username`,`password`,`nick_name`,`is_admin`,`phone`,`gender`,`birth`,`user_status`,`user_create_time`,`user_update_time`,`is_delete`,`is_member`,`balance`) values
(1,'aa','e10adc3949ba59abbe56e057f20f883e','666',1,'13566778899',1,'1990-07-18',0,'2021-10-15 10:56:40','2021-10-22 10:56:43',0,1,10000.00),
(2,'bb','bb','666',1,'111111',1,'1990-07-18',0,'2021-11-02 14:20:25','2021-11-03 09:25:58',0,1,1111.00),
(3,'cc','mark123','666',1,'13512341234',0,'1990-07-18',0,'2021-11-03 10:05:37','2021-11-03 10:05:37',0,1,10000.00),
(5,'dd','BB','666',1,'13512341234',0,'1990-07-18',0,'2021-11-03 10:15:00','2021-11-03 10:15:00',0,1,10000.00),
(6,'ee','CC','666',1,'13512341234',2,'1990-07-18',0,'2021-11-03 10:40:01','2021-11-03 10:40:01',0,1,10000.00),
(7,'ff','mark123','666',0,'13512341234',0,'1990-07-18',0,'2021-11-05 11:23:45','2021-11-05 11:23:45',0,1,10000.00);
导入依赖
mysql
mysql-connector-java
5.1.6
org.mybatis
mybatis
3.5.2
junit
junit
4.12
org.projectlombok
lombok
1.18.22
provided
实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Long userId;
private String username; //成员变量
private String password;
private String nickName;
private Integer isAdmin;
private String phone;
private Integer gender;
private Date birth;
private Integer userStatus;
private Date userCreateTime;
private Date userUpdateTime;
private Integer isDelete;
private Integer isMember;
private BigDecimal balance;
}
Mapper接口
public interface IUserMapper {
/**
* 查询所有
* @return
*/
List findAll();
}
SQL【Mapper】映射文件
全局配置文件
测试代码
/**
* mapper接口代理测试,掌握
**/
@Test
public void test02() {
SqlSession session = null;
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
session = sqlSessionFactory.openSession();
//获取mapper代理
IUserMapper userMapper = session.getMapper(IUserMapper.class);
List users = userMapper.findAll();
//mybatis能够帮我们自动完成查询结果集和实体间的映射,前提结果集列名和实体属性名相同
for (User user : users) {
System.out.println(user);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(null != session) {
session.close();
}
}
}
增删改操作涉及事务,务必要提交,查询不需要进行事务提交
Mapper接口
/**
* 增加
* @param user
*/
void save(User user);
Mapper映射文件
INSERT INTO t_user (
username,password,nick_name,is_admin,phone,gender,birth,user_status,
user_create_time,user_update_time,is_delete,is_member,balance)
VALUES
(#{username}, #{password}, #{nickName}, #{isAdmin}, #{phone}, #{gender}, #{birth}, #{userStatus},
#{userCreateTime}, #{userUpdateTime}, #{isDelete}, #{isMember}, #{balance})
测试类
/**
* 增加
**/
@Test
public void test03() throws Exception {
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession sqlSession = factory.openSession();
IUserMapper userMapper = sqlSession.getMapper(IUserMapper.class);
User user = new User();
user.setUsername("lucy");
user.setPassword("lucy123");
user.setNickName("露西");
user.setIsAdmin(0);
user.setPhone("13566778899");
user.setGender(0);
user.setBirth(java.sql.Date.valueOf("2005-10-30"));
user.setUserStatus(1);
user.setUserCreateTime(new Date());
user.setUserUpdateTime(new Date());
user.setIsDelete(0);
user.setIsMember(1);
user.setBalance(new BigDecimal(2000));
userMapper.save(user);
//提交事务
sqlSession.commit();
if(null != sqlSession) {
sqlSession.close();
}
}
主键自增
方式一【Mapper映射文件】
SELECT LAST_INSERT_ID()
INSERT INTO t_user
(username,password,nick_name,is_admin,phone,gender,birth,user_status,
user_create_time,user_update_time,is_delete,is_member,balance)
VALUES
(#{username}, #{password}, #{nickName}, #{isAdmin}, #{phone}, #{gender}, #{birth},
#{userStatus},#{userCreateTime}, #{userUpdateTime}, #{isDelete}, #{isMember}, #{balance})
方式二
INSERT INTO t_user
(username,password,nick_name,is_admin,phone,gender,birth,user_status,
user_create_time,user_update_time,is_delete,is_member,balance)
VALUES
(#{username}, #{password}, #{nickName}, #{isAdmin}, #{phone}, #{gender}, #{birth}, #{userStatus},
#{userCreateTime}, #{userUpdateTime}, #{isDelete}, #{isMember}, #{balance})
UPDATE t_user
SET PASSWORD = #{password}, nick_name = #{nickName}, user_update_time = #{userUpdateTime}
WHERE user_id = #{userId}
DELETE FROM t_user WHERE user_id = #{userId}
实体类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author ghy
* @version 1.0
* @date
**/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Stu {
private String stuId;
private String stuName;
}
Mapper接口和映射文件
SELECT REPLACE(UUID(), '-', '')
insert into t_stu (stu_id, stu_name) values (#{stuId},#{stuName})
Slf4j:接口【门面】
Log4j
Logback
commons-logging
没日志:很难判断问题来源
有日志:一般都可以判断问题来源。
可以通过日志把问题错误信息给记录下来
引入依赖
org.slf4j
slf4j-log4j12
1.7.7
log4j
log4j
1.2.17
日志配置文件【log4j.properties】
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=ssm.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
log4j.rootLogger=debug, stdout, file
日志级别
级别 | 描述 |
---|---|
ALL LEVEL | 打开所有日志记录开关;是最低等级的,用于打开所有日志记录。 |
DEBUG | 输出调试信息;指出细粒度信息事件对调试应用程序是非常有帮助的。【开发使用】 |
INFO | 输出提示信息;消息在粗粒度级别上突出强调应用程序的运行过程。【线上使用】 |
WARN | 输出警告信息;表明会出现潜在错误的情形。 |
ERROR | 输出错误信息;指出虽然发生错误事件,但仍然不影响系统的继续运行。 |
FATAL | 输出致命错误;指出每个严重的错误事件将会导致应用程序的退出。 |
OFF LEVEL | 关闭所有日志记录开关;是最高等级的,用于关闭所有日志记录。 |
直接使用API即可
package com.qf.java2107.test;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author ghy
* @version 1.0
* @date 2021-12-23
**/
public class LoggerTest {
Logger logger = LoggerFactory.getLogger(LoggerTest.class);
/**
*
**/
@Test
public void logTest() throws Exception {
logger.debug("debug---->{}", "debug level");
logger.info("info--->{}---{}", "aa", "bb");
logger.warn("warn----->");
logger.error("error---->");
}
}
基本数据类型及其包装类,String
Mapper映射文件获取参数值时,名称可以随意。但是强烈建议参数名跟形参名一致
JavaBean
Mapper映射文件获取参数值时,使用#{},{}中写JavaBean的属性名
Mapper映射文件获取参数值时,使用#{},{}中写Map中key的名称 |
---|
mybatis会把参数封装成一个Map,第一个参数的key为
arg0
【param1
】,第二参数的key为arg1
【param2
】,以此类推。以上方式不推荐使用,可读性太差。
Mapper映射文件获取参数值时,使用@Param来为Mapper接口方法指定入参的参数名,使用#{}取值
把查询结果集跟JavaBean进行映射绑定
当查询结果集的列名跟JavaBean属性名相同时,自动映射
当查询结果集的列名跟JavaBean属性名不相同时,需要手动映射
如果满足驼峰
使用别名进行映射【但是SQL太长】
全局配置文件【mybatis-config.xml】开启驼峰映射
自定义结果集映射
mybatis内部已经集成了结果集映射,就是Mapper映射文件的resultType
属性。resultType
底层使用其实也是ResultMap
resultType和resultMap最好只使用一个
如果满足驼峰并且不使用别名的情况下,可以使用resultType
resultMap可以在查询结果集封装中自定义使用。连表查询只能使用resultMap
resultMap的使用 |
---|
现在:会
以后:配置文件不见了,放到Spring中
全局配置文件支持的标签 |
---|
内置别名【推荐使用】 |
---|
自定义别名
可以屏蔽底层数据库的差异,实现同一API实现不同数据库的分页功能
Mybatis_PageHelper: Mybatis分页插件
导入依赖
com.github.pagehelper
pagehelper
5.1.10
全局配置文件
使用
Mapper映射文件
测试代码
/**
* 分页
**/
@Test
public void Test() throws Exception {
IUserMapper userMapper = sqlSession.getMapper(IUserMapper.class);
//分页设置跟查询之间不要出现其他操作
//参数一:页码
//参数二:显示条数
PageHelper.startPage(3, 5);
List list = userMapper.findAll();
PageInfo pageInfo = new PageInfo<>(list);
System.out.println("当前页:" + pageInfo.getPageNum());
System.out.println("当前页集合:" + pageInfo.getList());
System.out.println("总页数:" + pageInfo.getPages());
System.out.println("总条数:" + pageInfo.getTotal());
System.out.println("显示条数:" + pageInfo.getPageSize()); //显示条数
System.out.println("实际显示条数:" + pageInfo.getSize()); //实际显示条数
}
环境配置
用来加载Mapper映射文件
数据库层面
一对多:部门对员工、公司对部门
多对多:项目跟程序员、学生跟老师
多对一:学生对班级、员工对部门
一对一:人跟身份证、旅客跟护照
mybatis层面
一对多【多对多】
一对一【多对一】
一对多:查询部门关联查询员工
一对一:查询员工关联查询部门
数据库表
CREATE TABLE `t_department` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`dept_name` VARCHAR(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
INSERT INTO `t_department`(`id`,`dept_name`) VALUES
(1,'研发部'),
(2,'市场部'),
(3,'财务部'),
(4,'测试部');
CREATE TABLE `t_employee` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`emp_name` VARCHAR(20) NOT NULL,
`gender` INT(1) DEFAULT NULL COMMENT '1:男 0:女',
`birthday` DATE DEFAULT NULL,
`hire_date` DATETIME DEFAULT NULL,
`salary` INT(11) DEFAULT NULL,
`address` VARCHAR(200) DEFAULT NULL,
`dept_id` INT(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8;
INSERT INTO `t_employee`(`id`,`emp_name`,`gender`,`birthday`,`hire_date`,`salary`,`address`,`dept_id`) VALUES
(1,'宝宝',0,'2000-10-31','2021-10-01 09:00:00',8000,'杭州江干',2),
(2,'李四',1,'1985-11-10','2006-12-12 18:10:10',9000,'李家村',1),
(3,'王五',0,'1991-10-02','2009-12-02 00:00:00',1500,'王家村',2),
(5,'测试更新2',1,'2021-10-04','2021-11-11 00:00:00',15000,'杭州',2),
(7,'大CC',1,'2019-05-12','2021-11-07 00:00:00',6000,'杭州',2),
(8,'DD',1,'2021-11-05','2021-11-05 00:00:00',6000,'杭州',1),
(9,'九妹',0,'2021-11-11','2005-12-06 00:00:00',11111,'远古时期',NULL),
(10,'萧炎',1,'1999-12-12','2021-02-03 00:00:00',5000,'牛田村',1),
(11,'萧媚',1,'1985-11-11','2006-12-12 00:00:00',9000,'李家村',1),
(12,'小医仙',0,'1991-10-02','2009-12-02 00:00:00',1500,'王家村',2),
(13,'林动',1,'2021-11-05','2021-11-05 00:00:00',6000,'杭州',1),
(14,'凌青竹',1,'2021-11-05','2021-11-05 00:00:00',6000,'杭州',1),
(15,'纪宁',1,'2021-11-05','2021-11-05 00:00:00',6000,'杭州',2),
(16,'北冥',1,'2021-11-05','2021-11-05 00:00:00',6000,'杭州',1),
(17,'叶伏天',0,'2021-11-11','2005-12-06 00:00:00',11111,'远古时期',NULL),
(18,'余生',0,'2021-11-11','2005-12-06 00:00:00',11111,'远古时期',2),
(19,'花解语',0,'2021-11-11','2005-12-06 00:00:00',11111,'远古时期',1),
(100,'张三',1,'1999-12-12','2021-02-03 00:00:00',5000,'牛田村',1);
部门表跟员工表 |
---|
实体
部门 |
---|
员工 |
---|
根据ID查询部门信息且关联员工信息
2.2.1 修改部门实体
修改部门实体 |
---|
2.2.2 Mapper接口和Mapper映射文件
Mapper接口和Mapper映射文件 |
---|
Mapper接口
public interface IDepartmentMapper {
Department findByIdAndEmps(Integer id);
}
Mapper映射文件
根据ID查询员工信息且关联部门信息
2.3.1 修改员工实体
修改员工实体 |
---|
2.3.2 Mapper接口和Mapper映射文件
Mapper接口和Mapper映射文件 |
---|
Mapper接口
public interface IEmployeeMapper {
Employee findByIdAndDept(Integer id);
}
Mapper映射文件
是连表查询的另一种方式
把连表查询的SQL进行拆分出多个单表查询的SQL
查询部门信息关联查询员工信息
执行流程 |
---|
也叫懒加载,也叫按需加载
当需要使用到关联的数据时,才去执行查询操作
实现原理:Cglib动态代理【基于继承】
延迟加载只会出现在分步查询中。一般延迟加载的数据都是大数据【如集合】
即时加载:先执行完所有的SQL,再打印数据
延迟加载,先执行需要获取数据的SQL,再打印数据。后面如果还需要获取数据,再执行SQL,再打印数据
3.1 具体实现
全局配置文件开启延迟加载的开头
全局配置文件开启延迟加载的开头 |
---|
DepartmentMapper接口和映射文件
DepartmentMapper接口和映射文件 |
---|
测试
即时加载 |
---|
延迟加载 |
---|
if
choose (when, otherwise)
trim (where, set)
foreach
条件判断
成立,就拼接SQL
功能相当于数据库的where关键字
可以自定义的拼接或去掉SQL片段前后缀
SELECT
FROM t_employee
id,
emp_name,
gender,
birthday,
hire_date,
salary,
address,
dept_id
仅用于更新,跟if配套使用
update t_employee
emp_name = #{empName},
salary = #{salary},
gender = #{gender},
where id = #{id}
作用
提高查询效率
减轻数据库访问压力
一级缓存
二级缓存
一级缓存
级别:SqlSession
存储介质:内存
存储类型:对象副本
失效情况
二级缓存
级别:NameSpace
存储介质:磁盘
存储类型:散装数据
触发条件
Mybatis执行查询流程 |
---|
一级缓存默认开启,我们无法关闭他
在执行两次相同的查询时,第一次会向数据库发送SQL,并且写入一份到一级缓存中,那么后面的查询操作就直接从缓存中获取数据。不会向数据库发送SQL
一级缓存失效的情况
不是同一个SqlSession
两次相同的查询中间执行增删改
两次相同的查询中间手动清空缓存
两次相同的查询中间手动提交事务
@Test
public void firstLevelCacheTest() throws Exception {
IEmployeeMapper employeeMapper = sqlSession.getMapper(IEmployeeMapper.class);
Employee employee1 = employeeMapper.findById(10);
System.out.println(employee1);
//1.两个SqlSession
//sqlSession = factory.openSession();
//employeeMapper = sqlSession.getMapper(IEmployeeMapper.class);
//2.执行增删改
//employeeMapper.deleteById(111111);
//3.手动清空缓存
//sqlSession.clearCache();
//4.手动提交事务
sqlSession.commit();
Employee employee2 = employeeMapper.findById(10);
System.out.println(employee2);
System.out.println(employee1 == employee2);
}
二级缓存默认开启,我们可以通过配置文件对其关闭
二级缓存
必须在SqlSession关闭之后,数据才会被写入到二级缓存中。
存储介质是磁盘,所以写入的字节数据,那么要被写入的对象所在的类必须实现Serializable
接口
实现步骤
全局配置文件开启
在要使用二级缓存的namespace中配置一个
标签
关闭SqlSession
/**
* 二级缓存
**/
@Test
public void secondLevelCacheTest() throws Exception {
IEmployeeMapper employeeMapper = sqlSession.getMapper(IEmployeeMapper.class);
Employee employee1 = employeeMapper.findById(10);
System.out.println(employee1);
sqlSession.close();
sqlSession = factory.openSession();
employeeMapper = sqlSession.getMapper(IEmployeeMapper.class);
Employee employee2 = employeeMapper.findById(10);
System.out.println(employee2);
System.out.println(employee1 == employee2);
}
#{}
在填充参数时,是通过?
占位符的方式,能够避免SQL注入
只是获取跟数据库表列相关的值
${}
在填充参数时,使用的是直接进行字符串拼接,会有SQL注入的风险
使用其可以操作非数据库表列的取值
优先选择#{}取值,如果不行,则使用${}
注解开发跟配置文件开发,选择一种
package com.qf.java2107.mapper;
import com.qf.java2107.pojo.Department;
import org.apache.ibatis.annotations.*;
import java.util.List;
/**
* @author ghy
* @version 1.0
* @date 2021-12-27
**/
public interface IDepartmentMapper {
@Insert("insert into t_department (dept_name) values (#{deptName})")
@SelectKey(statement = "select last_insert_id()",
keyProperty = "id",
keyColumn = "dept_id",
before = false,
resultType = int.class)
int save(Department department);
/**
* @Results 等同于配置文件的resultMap标签
* id 等同于配置文件的resultMap标签中id属性
*
* @Result : 映射单个属性,用boolean来区分是否是主键映射
*/
@Results(
id = "BaseResultMap",
value = {
@Result(id = true, column = "id", property = "id"),
@Result(id = false, column = "dept_name", property = "deptName")
}
)
@Select("select id, dept_name from t_department")
List findAll();
@ResultMap("BaseResultMap") //引用其他已经定义好的ResultMap
@Select("select id, dept_name from t_department where id = #{id}")
Department findById(Integer id);
}
分步查询【IEmployeeAnnoMapper.class】
package com.qf.java2107.mapper;
import com.qf.java2107.pojo.Employee;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.mapping.FetchType;
/**
* @author ghy
* @version 1.0
* @date 2021-12-27
**/
public interface IEmployeeAnnoMapper {
/**
* 根据ID查询员工关联部门
* @param id
* @return
*/
@Results({
@Result(id = true, column = "id", property = "id"),
@Result(id = false, column = "emp_name", property = "empName"),
@Result(id = false, column = "gender", property = "gender"),
@Result(id = false, column = "birthday", property = "birthday"),
@Result(id = false, column = "hire_date", property = "hireDate"),
@Result(id = false, column = "salary", property = "salary"),
@Result(id = false, column = "address", property = "address"),
@Result(id = false, column = "dept_id", property = "deptId"),
@Result(id = false, property = "dept", column = "dept_id",
//one 一对一映射
one = @One(select = "com.qf.java2107.mapper.IDepartmentMapper.findById",
fetchType = FetchType.LAZY))
})
@Select("select * from t_employee where id = #{id}") //dept_id
Employee findByIdUseStep(Integer id);
}
查询单个
DefaultSqlSession的selectOne方法
DefaultSqlSession的selectList方法,得到结果后,进行集合数量判断,如果是1,直接返回。>1,否则就报错。0返回null
CachingExecutor的query方法
BaseExecutor的query方法
BaseExecutor的queryFromDatabase方法
BaseExecutor的doQuery方法
通过SimpleExecutor中去调用JDBC的execute()
查询集合
DefaultSqlSession的selectList方法,得到结果后,直接返回
CachingExecutor的query方法
BaseExecutor的query方法
BaseExecutor的queryFromDatabase方法
BaseExecutor的doQuery方法
通过SimpleExecutor中去调用JDBC的execute()
修改
DefaultSqlSession的update方法
CachingExecutor的update方法:会清空缓存操作
BaseExecutor的doUpdate方法
通过SimpleExecutor中去调用JDBC的execute()
增加、删除
先调用DefaultSqlSession的insert方法或者delete方法
接下来就会执行DefaultSqlSession的update方法
构建者模式
工厂模式
代理模式
不支持
mapper接口的方法名就是mapper映射文件的statementId,是用来获取执行SQL的唯一标识
除之前讲的之外
sql:抽取的SQL片段
include:引用抽取的SQL片段
SELECT
FROM t_employee
id,
emp_name,
gender,
birthday,
hire_date,
salary,
address,
dept_id