网站建设的行业分析深圳福田教育
ok了家人们,今天学习了mybatis这个框架,我们一起去看看吧

一.Mybatis简介
1.1 Mybatis概述
 MyBatis 最初是 Apache 的一个开源项目 iBatis, 2010 年 6 月  
 
 这个项目由 Apache Software Foundation 迁移到了  
 
 Google Code 。随着开发团队转投 Google Code 旗下,  
 
 iBatis3.x 正式更名为 MyBatis 。代码于 2013 年 11 月迁移到  
 
 Github 。  
 
 
 MyBatis  是一款优秀的持久层框架,用于简化  JDBC  开  
  发。它支持自定义  SQL 、存储过程以及高级映射。  
  MyBatis  免除了几乎所有的  JDBC  代码以及设置参数和获  
  取结果集的工作。 MyBatis  可以通过简单的  XML  或注解来  
  配置和映射原始类型、接口和  Java POJO ( Plain Old Java  
  Objects ,普通老式  Java  对象)为数据库中的记录。  
   官网: https://mybatis.org/mybatis-3/zh/index.html 
  1.2 浅谈JDBC代码
public class DemoTest {public static void main(String[] args) {//1. 注册驱动Class.forName("com.mysql.jdbc.Driver");//2. 获取Connection连接String url = "jdbc:mysql:///db1? useSSL=false";String uname = "root";String pwd = "1234";Connection conn =DriverManager.getConnection(url, uname, pwd);// 接收输入的查询条件String gender = "男";// 定义sqlString sql = "select * from tb_user where gender = ?";// 获取pstmt对象PreparedStatement pstmt =conn.prepareStatement(sql);// 设置?的值pstmt.setString(1,gender);// 执行sqlResultSet rs = pstmt.executeQuery();// 遍历Result,获取数据User user = null;ArrayList<User> users = new ArrayList<>();while (rs.next()) {//获取数据int id = rs.getInt("id");String username =rs.getString(“username”);String password =rs.getString(“password”);//创建对象,设置属性值user = new User();user.setId(id);user.setUsername(username);user.setPassword(password);user.setGender(gender);//装入集合users.add(user);}//释放资源rs.colse();pstmt.colse();conn.close();}
} 
- 硬编码
 
 注册驱动、获取连接。连接数据库的四个基本信息,以  
  后如果要将 Mysql 数据库换成其他的关系型数据库的  
  话,这四个地方都需要修改,如果放在此处就意味着要  
  修改我们的源代码。  
   如果表结构发生变化, SQL 语句就要进行更改。这也不  
  方便后期的维护。 
  - 操作繁琐
 
 手动设置参数  
   手动封装结果集 
   MyBatis : SQL  和  Java  编码分开,功能边界清晰。 Java 代码专  
  注业务、 SQL 语句专注数据 
   MyBatis :免除了几乎所有的  JDBC  代码以及设置参数和获取  
  结果集的工作 
  1.3 框架名词解释
- 框架就是一个半成品软件,是一套可重用的、通用的、软件基础代码模型
 -  在框架的基础之上构建软件编写更加高效、规范、通用、可扩展
 
二.快速入门(基于Mybatis3方式)
2.1 入门案例实现步骤
- 创建数据库和表
 - 创建模块,导入坐标
 - 实体类准备
 - 编写Mybatis核心配置文件
 - 编写Mapper接口
 - 编写 SQL 映射文件
 - 测试
 
创建数据库和表
CREATE TABLE t_emp(
emp_id INT primary key AUTO_INCREMENT,
emp_name CHAR(100),
emp_salary DOUBLE(10,5)
);
INSERT INTO t_emp(emp_name,emp_salary)
VALUES("张三",200.33);
INSERT INTO t_emp(emp_name,emp_salary)
VALUES("李四",200.44);
INSERT INTO t_emp(emp_name,emp_salary)
VALUES("王五",200.55);  创建模块,导入坐标 
  <dependencies>
<!-- mybatis依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
<!-- MySQL驱动 mybatis底层依赖jdbc驱动实现,本次
不需要导入连接池,mybatis自带! -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connectorjava</artifactId>
<version>8.0.25</version>
</dependency><!--junit5测试-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiterapi</artifactId>
<version>5.3.1</version>
</dependency>
</dependencies>  实体类准备              
    
               
          
       
                                                
 public class Employee {
private Integer empId;
private String empName;
private Double empSalary;
public Integer getEmpId() {
return empId;
}
public void setEmpId(Integer empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Double getEmpSalary() {
return empSalary;
}
public void setEmpSalary(Double empSalary) {
this.empSalary = empSalary;
}
@Override
public String toString() {
return "Employee{" +
"empId=" + empId +
", empName='" + empName + '\'' +
", empSalary=" + empSalary +
'}';
}
}  编写 Mybatis 核心配置文件  
  - 替换连接信息 解决硬编码问题
 -  在模块下的 resources 目录下创建 mybatis 的配置文件mybatis-config.xml
 
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config
3.0//EN"
"https://mybatis.org/dtd/mybatis-3-
config.dtd">
<!--configuration表示mybatis框架的核心配置文件的根标
签,配置-->
<configuration>
<!--
environments:表示当前mybatis框架的环境:开发
测试环境等
一个environments标签下面可以书写多个
environment
一个environment标签代表一个环境
-->
<environments default="development">
<environment id="development">
<!--
事务管理,这里先使用mybatis框架的默认
管理type="JDBC",实际开发中
mybatis框架的事务由spring框架
-->
<transactionManager type="JDBC">
</transactionManager>
<!---->
<dataSource type="POOLED">
<property name="driver"
value="com.mysql.cj.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/ssm_01"/><property name="username"
value="root"/>
<property name="password"
value="123456"/>
</dataSource>
</environment>
</environments>
<!--加载映射配置文件-->
<mappers>
<mapper resource="EmployeeMapper.xml">
</mapper>
</mappers>
</configuration> 编写Mapper接口
 Mybatis  中的  Mapper  接口相当于以前的  Dao 。但是区别在  
  于, Mapper  仅仅只是建接口  
 package com.lzw.mapper;
import com.lzw.pojo.Employee;
import java.util.List;
//接口只规定方法,参数和返回值!映射配置文件中编写具体SQL
语句!
public interface EmployeeMapper {
public List<Employee> findAll();
}  编写  SQL  映射文件 
  - 统一管理sql语句,解决硬编码问题
 -  在模块的 resources 目录下创建映射配置文件EmployeeMapper.xml
 
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper
3.0//EN"
"https://mybatis.org/dtd/mybatis-3-
mapper.dtd">
<!--namespace:名称空间 该映射配置文件和哪个Mapper接口
进行映射绑定-->
<mapper
namespace="com.lzw.mapper.EmployeeMapper">
<!--
id:唯一标识,映射接口的方法
resultType:输出的参数类型
-->
<select id="findAll"
resultType="com.lzw.pojo.Employee">
select emp_id empId,emp_name
empName,emp_salary empSalary from t_emp
</select>
</mapper>  测试 
  public class DemoTest {
//入门案例
@Test
public void test01() throws IOException {
//读取核心配置文件
InputStream in =
Resources.getResourceAsStream("mybatisconfig.xml");
//构建SqlSessionFactory工厂对象
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(in);
//通过SqlSessionFactory工厂对象获取SqlSession对象(就是connection)
SqlSession sqlSession =
sqlSessionFactory.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
List<Employee> employeeList =
employeeMapper.findAll();
//处理结果
for (Employee employee : employeeList) {
System.out.println(employee);
}
//释放资源
sqlSession.close();
}
} 2.2 Lombok插件的使用(简化代码)
 使用 Lombok 注解就可以省略生成 getXxx() 、 setXxx() 方法、  
  toString() 方法、构造器等固定格式代码的繁琐操作,提高开  
  发效率。包括 Logger 日志对象。  
   Lombok 原理: Lombok 是将自动生成的代码织入字节码文件  
  中,从而实现:源代码没有,但是字节码文件有 —— 毕竟我们  
  最终运行的是字节码文件,只要字节码文件中有即可。而这个  
  过程因为要参与源文件编译,所以需要安装 IDEA 插件。 
   Lombok 安装 
 
  加入依赖 
    <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version></dependency>  注解功能介绍  
  |    注解    |    作用    | 
|    @Data     |    生成 getXxx() 方法、 setXxx() 方     法、 toString() 、 equals() 、     canEqual() 、 hashCode() 方法    | 
|    @AllArgsConstructor    |    生成全参构造器     | 
|    @NoArgsConstructor    |    生成无参构造器    | 
|    @Slf4j     |    生成日志对象    | 
|    @Getter    |    生成 getXxx() 方法    | 
|    @Setter     |    生成 setXxx() 方法    | 
|    @ToString    |    生成 toString() 方法    | 
 使用 Lombok  
  package com.cjx.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {private Integer empId;private String empName;private Double empSalary;
}
 2.3 日志框架(便于调试)
2.3.1 用日志打印替代sout
 sout 有什么问题 
   System.out 对象是一个输出流对象,所以控制台输出信息  
  本质上是 I/O 操作。而 I/O 操作是项目运行过程中两大性能  
  瓶颈之一。  
   项目上线时,希望把所有(或一部分) sout 打印关闭,但  
  是只能手动一个一个查找,耗费开发人员的极大精力,因  
  为 sout 的无度使用会使它分散在项目的各个角落。  
   使用 [ 日志框架 ] 的好处 
   设定级别,统一管理。日志框架会按照事件的严重程度来  
  划分级别,例如:  
           错误(Error ):表示程序运行出错,比如抛异常等情  
          况。  
           警告(Warning ):表示程序运行过程中有潜在风险,  
          但此时并没有报错。  
           信息(Info ):表示程序运行过程中完成了一个关键动  
          作,需要以程序运行信息的形式告知开发者。  
           调试(Debug ):表示程序运行过程中更加细致的信  
          息,协助程序员调试程序。 
   灵活指定输出位置 
           使用日志框架不一定是打印到控制台,也可以保存到文  
          件中或者保存到数据库。这就看具体的项目维护需求。 
   自定义日志格式  
           打印日志数据可以使用日志框架的默认格式,也可以根  
          据需要定制。  
   基于日志分析问题 
           将来我们开发的应用系统中,不仅包含Java 代码,还有  
          很多中间件服务器。任何子系统出现故障我们都是通过  
          日志来定位问题、分析故障原因。甚至更复杂的系统还  
          会专门开发日志子系统,在主系统出现问题时抓取日志  
          数据供维护人员参考。而日志数据必须要有确定格式才  
          便于格式化和抓取,这肯定不是随意写sout 就能实现  
          的。 
   通过在配置文件中指定某一个日志级别来控制系统要打印的内  
  容。日志框架会打印 当前指定级别 的日志和比当前指定级别 更  
  严重 的级别的日志。  
  例如在开发阶段,我们指定 debug 级别,项目上线修改成 info  
  级别,那么所有 debug 级别的日志就都不打印了,不需要到项  
  目代码中一个一个修改,非常方便。 
  2.3.2 Java日志体系演变
门面:类似于标准层、接口层
|    名称    |    说明    | 
|    JCL ( Jakarta Commons Logging )    |    陈旧     | 
|    SLF4J ( Simple Logging Facade for Java)    |    适合( 同一作 者 )    | 
|    jboss-logging     |    特殊专业领域使用    | 
 实现  
 |    名称    |    说明    | 
|    log4j     |    最初版( 同一作者 )    | 
|    JUL     ( java.util.logging )    |    JDK 自带    | 
|    log4j2    |    Apache 收购 log4j 后全面重构,     内部实现和 log4j 完全不同     | 
|    logback     |    优雅、强大( 同一作者 )    | 
 最佳拍档  
  - 门面:SLF4J
 - 实现:logback
 
2.3.3 日志用法
- 依赖导入
 
<!-- 日志 会自动传递slf4j门面-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency> - 引入配置
 
 Logback 要求配置文件名称必须是 logback.xml ,存放路径在  
  main/resources 目录下。  
   通过配置文件,可以配置输出格式、输出级别、输出位置等!  
  <?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
<!-- 指定日志输出的位置,ConsoleAppender表示输出
到控制台 -->
<appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- 日志输出的格式 -->
<!-- 按照顺序分别是:时间、日志级别、线程
名称、打印日志的类、日志主体内容、换行 -->
<pattern>[%d{HH:mm:ss.SSS}]
[%-5level] [%thread] [%logger]
[%msg]%n</pattern>
<charset>UTF-8</charset>
</encoder>
2.4 工具类抽取(简化代码)
</appender>
<!-- 设置全局日志级别。日志级别按顺序分别是:
TRACE、DEBUG、INFO、WARN、ERROR -->
<!-- 指定任何一个日志级别都只打印当前级别和后面级别
的日志。 -->
<root level="DEBUG">
<!-- 指定打印日志的appender,这里通
过“STDOUT”引用了前面配置的appender -->
<appender-ref ref="STDOUT" />
</root>
<!-- 根据特殊需求指定局部日志级别,可也是包名或全类
名。 -->
<logger name="com.lzw.mapper" level="DEBUG"
/>
</configuration> 2.4 工具类抽取(简化代码)
package com.cjx.utils;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 java.io.IOException;
import java.io.InputStream;public class SqlSessionUtil {private static SqlSessionFactory sqlSessionFactory=null;static {try {//读取核心配置文件InputStream in = Resources.getResourceAsStream("mybatis-config.xml");//构建SqlSessionFactory工厂对象sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);} catch (IOException e) {e.printStackTrace();}}public static SqlSession openSession(){//通过SqlSessionFactory工厂对象获取SqlSession对象(就是connection)SqlSession sqlSession = sqlSessionFactory.openSession();return sqlSession;}
} package com.cjx.test;import com.cjx.mapper.EmployeeMapper;
import com.cjx.pojo.Employee;
import com.cjx.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;import java.util.HashMap;
import java.util.List;
import java.util.Map;public class DemoTest {//查询所有@Testpublic void test01(){//获取SqlSessionSqlSession sqlSession = SqlSessionUtil.openSession();//基于接口获取实现类对象(代理对象)EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//通过多态调用方法List<Employee> employeeList = employeeMapper.findAll();//处理结果for (Employee employee : employeeList) {System.out.println(employee);}//释放资源sqlSession.close();}
 2.5 增删改查
- Mapper接口
 
package com.cjx.mapper;import com.cjx.pojo.Employee;
import org.apache.ibatis.annotations.Param;import java.util.List;
import java.util.Map;public interface EmployeeMapper {//查询所有数据List<Employee> findAll();//查询单个数据Employee findEmpById(Integer empId);//添加一条数据public Integer insertEmp(Employee employee);//修改一条数据public Integer updateEmp(Employee employee);//删除一条数据public Integer deleteEmpById(Integer empId);//修改一条数据 零散的简单类型数据public Integer updateEmpById(@Param("empName") String empName,@Param("empSalary") double empSalary,@Param("empId") Integer empId);//修改一条数据public Integer update(Map<String,Object> map);
}
 - 映射配置文件
 
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace:名称空间 接口的全限定名-->
<mapper namespace="com.cjx.mapper.EmployeeMapper"><!--id:唯一标识 接口的方法名保持一致--><!--结果类型:如果是集合 写集合的元素的类型--><select id="findAll"  resultType="Employee">select * from t_emp</select><select id="findEmpById" parameterType="int" resultType="Employee">select emp_id,emp_name,emp_salary from t_emp where emp_id=#{empId}</select><insert id="insertEmp">insert into t_emp values(null,#{empName},#{empSalary})</insert><update id="updateEmp">update t_emp set emp_name=#{empName},emp_salary=#{empSalary} where emp_id=#{empId}</update><delete id="deleteEmpById" parameterType="int">delete from t_emp where emp_id=#{empId}</delete><update id="updateEmpById">update t_emp set emp_name=#{empName},emp_salary=#{empSalary} where emp_id=#{empId}</update><update id="update" parameterType="Map">update t_emp set emp_name=#{empName},emp_salary=#{empSalary} where emp_id=#{empId}</update>
</mapper> - 测试
 
package com.cjx.test;import com.cjx.mapper.EmployeeMapper;
import com.cjx.pojo.Employee;
import com.cjx.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;import java.util.HashMap;
import java.util.List;
import java.util.Map;public class DemoTest {//查询所有@Testpublic void test01(){//获取SqlSessionSqlSession sqlSession = SqlSessionUtil.openSession();//基于接口获取实现类对象(代理对象)EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//通过多态调用方法List<Employee> employeeList = employeeMapper.findAll();//处理结果for (Employee employee : employeeList) {System.out.println(employee);}//释放资源sqlSession.close();}//通过Id查询数据@Testpublic void test02(){//获取SqlSessionSqlSession sqlSession = SqlSessionUtil.openSession();//基于接口获取实现类对象(代理对象)EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//通过多态调用方法Employee emp = employeeMapper.findEmpById(1);//处理结果System.out.println(emp);//释放资源sqlSession.close();}//新增一条数据@Testpublic void test03(){//获取SqlSessionSqlSession sqlSession = SqlSessionUtil.openSession();//基于接口获取实现类对象(代理对象)EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//通过多态调用方法Employee employee = new Employee(null,"赵六",260.0);Integer emp = employeeMapper.insertEmp(employee);//处理结果System.out.println(emp);//提交事务sqlSession.commit();//释放资源sqlSession.close();}//修改一条数据根据Id@Testpublic void test04(){//获取SqlSessionSqlSession sqlSession = SqlSessionUtil.openSession();//基于接口获取实现类对象(代理对象)EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//通过多态调用方法Employee employee = new Employee(1,"zs",230.0);Integer emp = employeeMapper.updateEmp(employee);//处理结果System.out.println(emp);//提交事务sqlSession.commit();//释放资源sqlSession.close();}//删除一条数据根据Id@Testpublic void test05(){//获取SqlSessionSqlSession sqlSession = SqlSessionUtil.openSession();//基于接口获取实现类对象(代理对象)EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//通过多态调用方法Integer emp = employeeMapper.deleteEmpById(4);//处理结果System.out.println(emp);//提交事务sqlSession.commit();//释放资源sqlSession.close();}//修改一条数据根据Id@Testpublic void test07(){//获取SqlSessionSqlSession sqlSession = SqlSessionUtil.openSession();//基于接口获取实现类对象(代理对象)EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//通过多态调用方法Integer emp = employeeMapper.updateEmpById("ww",255.55,3);//处理结果System.out.println(emp);//提交事务sqlSession.commit();//释放资源sqlSession.close();}//修改一条数据根据Id@Testpublic void test06(){//获取SqlSessionSqlSession sqlSession = SqlSessionUtil.openSession();//基于接口获取实现类对象(代理对象)EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//通过多态调用方法Map<String,Object> map = new HashMap<>();map.put("empName","ls");map.put("empSalary",244.44);map.put("empId",2);Integer emp = employeeMapper.update(map);//处理结果System.out.println(emp);//提交事务sqlSession.commit();//释放资源sqlSession.close();}
}
 - 注意事项
 
 插入操作涉及数据库数据变化,所以要使用 sqlSession 对象显  
  示的提交事务,即 sqlSession.commit()  
   增删改接口的返回值是 Integer, 表示返回影响的行数 , 在映射配  
  置文件中不需要设置 resultType 
  三. MyBatis核心配置文件
 MyBatis  的核心配置文件包含了会深深影响  MyBatis  行为的  
  设置和属性信息。 配置文档的顶层结构如下:  
  - configuration(配置)  
- properties(属性)
 - settings(设置)
 - typeAliases(类型别名)
 - typeHandlers(类型处理器)
 - objectFactory(对象工厂)
 - plugins(插件)
 - environments(环境配置)  
- environment(环境变量)  
- transactionManager(事务管理器)
 - dataSource(数据源)
 
 
 - environment(环境变量)  
 
 - databaseIdProvider(数据库厂商标识)
 - mappers(映射器)
 
 注意事项:在配置时按照以上顺序进行配置  
  3.1 properties(属性)
 实际开发中,习惯将数据源的配置信息单独抽取成一个  
  properties 文件,该标签可以加载额外配置的 properties 文  
  件。 
  - db.properties
 
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm_01
jdbc.username=root
jdbc.password=123456 - mybatis-config.xml
 
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""https://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!--加载外部properties--><properties resource="db.properties"></properties><!--开启自动映射 驼峰命名--><settings><setting name="mapUnderscoreToCamelCase" value="true"/></settings><!--起别名--><typeAliases><package name="com.cjx.pojo"/></typeAliases><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><!--8.x--><property name="driver" value="${jdbc.driver}"/><!--5.x--><!-- <property name="driver" value="com.mysql.jdbc.Driver"/>--><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><!--核心配置文件加载映射配置文件--><mappers><mapper resource="EmployeeMapper.xml"/></mappers>
</configuration> 3.2 settings(设置)
|    设置名     |    描述     | 
|    mapUnderscoreToCamelCase     |    是否开启驼峰命名自动     映射,即从经典数据库     列名  A_COLUMN  映射     到经典  Java  属性名     aColumn 。 取值: true     | false  默认值: false    | 
<!--开启驼峰映射-->
<settings>
<setting name="mapUnderscoreToCamelCase"
value="true"/>
</settings> 3.3 typeAliases(类型别名)
 类型别名可为  Java  类型设置一个缩写名字。 它仅用于  XML  
  配置,意在降低冗余的全限定类名书写。 
   <typeAliases><package name="com.cjx.pojo"/></typeAliases> 3.4 environments(环境配置)
 MyBatis  可以配置成适应多种环境,这种机制有助于将  SQL  
  映射应用于多种数据库之中, 现实情况下有多种理由需要这  
  么做。例如,开发、测试和生产环境需要有不同的配置。  
   不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory  实例只能选择一种环境。 
  <environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><!--8.x--><property name="driver" value="${jdbc.driver}"/><!--5.x--><!-- <property name="driver" value="com.mysql.jdbc.Driver"/>--><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments> 四.数据输入
- 简单类型:只包含一个值的数据类型  
- 基本数据类型:int、byte、short、double、……
 - 基本数据类型的包装类型:Integer、Character、Double、……
 - 字符串类型:String
 
 - 复杂类型:包含多个值的数据类型  
- 实体类类型:Employee、Department、……
 - 集合类型:List、Set、Map、……
 - 数组类型:int[]、String[]、……
 - 复合类型:List<Employee>、实体类中包含集合……
 
 
4.1 参数占位符
 #{}  :执行 SQL 时,会将  #{}  占位符替换为?,将来自动设  
  置参数值。从案例可以看出使用 #{}  底层使用的是  
  PreparedStatement 。  
  public interface EmployeeMapper {
//查询单个数据
public Employee findEmpById01(Integer
empId);
} <select id="findEmpById01" parameterType="int"
resultType="Employee">
select * from t_emp where emp_id = #{empId}
</select> 
 ${}  :拼接 SQL 。底层使用的是  Statement ,会存在 SQL 注入问题 
  public interface EmployeeMapper {
//查询单个数据
public Employee findEmpById02(Integer
empId);
} <select id="findEmpById02" parameterType="int"
resultType="Employee">
select * from t_emp where emp_id = ${empId}
</select> 
 结论:实际开发中,能用 #{} 实现的,肯定不用 ${} 。  
  4.2 parameterType使用
 对于有参数的 mapper 接口方法,我们在映射配置文件中应该  
  配置  ParameterType  来指定参数类型。只不过该属性都可以  
  省略。 
  <insert id="insertEmp" parameterType="Employee">
insert into t_emp values(null,#{empName},#
{empSalary})
</insert> 4.3 单个简单类型参数
4.3.1 编写接口方法
public interface EmployeeMapper {
//删除一条数据
public Integer deleteEmpById(Integer empId);
} 4.3.2 编写SQL语句
<delete id="deleteEmpById"
parameterType="java.lang.Integer">
delete from t_emp where emp_id = #{empId}
</delete> -  增删改接口的返回值是 Integer, 表示返回影响的行数 , 在映射配置文件中不需要设置 resultType
 -  单个简单类型参数,在 #{} 中可以随意命名,但是没有必要。通常还是使用和接口方法参数同名。
 
4.3.3 编写测试方法
 //删除一条数据根据Id@Testpublic void test05(){//获取SqlSessionSqlSession sqlSession = SqlSessionUtil.openSession();//基于接口获取实现类对象(代理对象)EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//通过多态调用方法Integer emp = employeeMapper.deleteEmpById(4);//处理结果System.out.println(emp);//提交事务sqlSession.commit();//释放资源sqlSession.close();} 4.4 实体类类型参数
 将多个参数封装成一个 实体对象 ,将该实体对象作为接口的  
  方法参数。该方式要求在映射配置文件的 SQL 中使用  #{ 内容 }  
  时,里面的内容必须和实体类属性名保持一致。 
  4.4.1 编写接口方法
public interface EmployeeMapper {
//添加一条数据
public Integer insertEmp(Employee employee);
} 4.4.2 编写SQL语句
<!--实体传参,在映射配置文件中取值,直接写对象的属性名-->
<insert id="insertEmp" parameterType="Employee">
insert into t_emp values(null,#{empName},#
{empSalary})
</insert> 4.4.3 编写测试方法
@Test
public void testInsert(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Employee employee=new Employee(null,"王五",555.22);
Integer row = employeeMapper.insertEmp(employee);
//输出结果
System.out.println(row);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
} 4.5 零散的简单类型数据
 零散的多个简单类型参数,如果没有特殊处理,那么 Mybatis  
  无法识别自定义名称: 
  4.5.1 编写接口方法
public interface EmployeeMapper {
//根据ID修改员工姓名
public Integer updateNameById(String
empName,Integer empId);
} 4.5.2 编写SQL语句
<update id="updateNameById">
update t_emp set emp_name = #{empName} where
emp_id = #{empId}
</update> 4.5.3 编写测试方法
@Test
public void testupdateNameById(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Integer row =
employeeMapper.updateNameById("zs",1);
//输出结果
System.out.println(row);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
} 
4.5.4 解决方案
- 修改配置文件取值方式
 
<update id="updateNameById">
update t_emp set emp_name = #{param1} where
emp_id = #{param2}
</update> -  使用 @Param(" 参数名称 ") 标记每一个参数,在映射配置文件中就需要使用 #{ 参数名称 } 进行占位
 
public interface EmployeeMapper {
//根据ID修改员工姓名
public Integer
updateNameById(@Param("empName") String empName,
@Param("empId") Integer empId);
} <update id="updateNameById">
update t_emp set emp_name = #{empName} where
emp_id = #{empId}
</update> 4.6 Map类型参数
 将多个参数封装到 map 集合中,将 map 集合作为接口的方法  
  参数。该方式要求在映射配置文件的 SQL 中使用  #{ 内容 }  时,  
  里面的内容必须和 map 集合中键的名称一致。  
  4.6.1 编写接口方法
public interface EmployeeMapper {
//修改一条数据
public Integer updateEmp(Map<String,Object>
map);
} 4.6.2 编写SQL语句
<!--通过key获取value的值-->
<update id="updateEmp" parameterType="Employee">
update t_emp set emp_name = #
{empName},emp_salary = #{empSalary} where
emp_id = #{empId}
</update> 4.6.3 编写测试代码
@Test
public void testUpdate(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Map<String,Object> map=new HashMap<>();
map.put("empId",3);
map.put("empName","ww");
map.put("empSalary",55.33);
Integer row = employeeMapper.updateEmp(map);
//输出结果
System.out.println(row);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
} 五.数据输出
5.1 输出概述
 数据输出总体上有两种形式: 
 -  增删改操作返回受影响行数:直接在接口方法中使用 int或 long 类型接收即可
 -  查询操作的查询结果
 
 我们需要做的是,指定查询的输出数据类型即可!  
 
 
 并且插入场景下,实现主键数据回显示!  
 
 
 resultType = " 全限定符 | 别名 | 如果是返回集合类型,写  
 
 范型类型即可 
 
 
5.2 返回单个简单类型
5.2.1 编写接口方法
public interface EmployeeMapper {
//查询总条数
public Integer findTotalCount();
} 
5.2.2 编写SQL语句
<select id="findTotalCount" resultType="int">
select count(*) from t_emp
</select> 
5.2.3 编写测试代码
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Integer totalCount =
employeeMapper.findTotalCount();
//输出结果
System.out.println(totalCount);
//释放资源
sqlSession.close();
} 
5.3 返回实体类对象
5.3.1 编写接口方法
public interface EmployeeMapper {
//根据ID查询用户信息
public Employee findEmpById(Integer empId);
} 
5.3.2 编写SQL语句
<select id="findEmpById" parameterType="int"
resultType="Employee">
select * from t_emp where emp_id = #{empId}
</select> 
5.3.3 编写测试代码
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Employee employee =
employeeMapper.findEmpById(1);
//输出结果
System.out.println(employee);
//释放资源
sqlSession.close();
} 
5.4 返回List类型
 查询结果返回多个实体类对象,希望把多个实体类对象放在  
 
 List 集合中返回。此时不需要任何特殊处理,在 resultType 属  
 
 性中还是设置实体类类型即可。  
 
 
 5.4.1  编写接口方法  
  public interface EmployeeMapper {
//查询所有数据
public List<Employee> findAll();
}  5.4.2  编写 SQL 语句 
  <select id="findAll" resultType="Employee">
select * from t_emp
</select> 5.4.3 编写测试代码
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
List<Employee> employeeList =
employeeMapper.findAll();
//输出结果
for (Employee employee : employeeList) {
System.out.println(employee);
}
//释放资源
sqlSession.close();
} 5.5 返回Map类型
 适用于 SQL 查询返回的各个字段综合起来并不和任何一个现有  
  的实体类对应,没法封装到实体类对象中。  
  5.5.1 编写接口方法
public interface EmployeeMapper {
//查询所有员工的最高工资,最低工资,平均工资
public Map<String,Object> findSalary();
} 5.5.2 编写SQL语句
<select id="findSalary" resultType="Map">
select max(emp_salary) 最高工资,min(emp_salary) 最低工资,avg(emp_salary) 平局工资 from t_emp
</select> 5.5.3 编写测试代码
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Map<String, Object> map =
employeeMapper.findSalary();
//输出结果
Set<Map.Entry<String, Object>> entrySet =
map.entrySet();
for (Map.Entry<String, Object> entry :
entrySet) {
System.out.println(entry.getKey()+"..."+entry.g
etValue());
}
//释放资源
sqlSession.close();
} 5.6 主键回填
5.6.1 自增长类型主键
public interface EmployeeMapper {
//添加数据
public Integer insertEmp(Employee employee);
} <!--
主键回填:当Mybatis执行新增后,会将数据库中该
条数据新增后的主键回填到实体的属性上
useGeneratedKeys:是否启用主键回填
keyProperty:指定主键回填到实体的哪个属性上
keyColumn:指定数据库中哪一列是主键(可选)
-->
<insert id="insertEmp" parameterType="Employee"
useGeneratedKeys="true" keyProperty="empId">
insert into t_emp values(null,#{empName},#
{empSalary})
</insert> @Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Employee employee=new Employee(null,"赵
六",11.22);
Integer integer =
employeeMapper.insertEmp(employee);
//输出结果
System.out.println(integer);
//后续需要完善员工信息
System.out.println(employee);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
} 5.6.2 非自增长类型主键
 而对于不支持自增型主键的数据库或者字符串类型主键,则可  
  以使用  selectKey  子元素: selectKey  元素将会首先运行, id  
  会被设置,然后插入语句会被调用!  
   使用  selectKey  帮助插入 UUID 作为字符串类型主键示例: 
  CREATE TABLE t_user (
id varchar(64) primary key,
username varchar(50),
password varchar(50)
) public interface UserMapper {
//添加数据
public Integer insertUser(User user);
} <mapper namespace="com.lzw.mapper.UserMapper">
<insert id="insertUser"
parameterType="user">
<!--
keyProperty:设置为实体的哪个属性,
resultType:设置返回值类型,
order:值为after和before
after: sql之后执行,before: sql之前执行
-->
<selectKey order="BEFORE"
resultType="string" keyProperty="id">
select replace(UUID(),'-','')
</selectKey>
insert into t_user values(#{id},#
{username},#{password})
</insert>
</mapper> @Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
UserMapper userMapper =
sqlSession.getMapper(UserMapper.class);
//通过多态调用方法
//String id=
UUID.randomUUID().toString().replace("-","");
User user=new User(null,"zs","123456");
Integer integer =
userMapper.insertUser(user);
//输出结果
System.out.println(integer);
//后续需要完善用户信息
System.out.println(user);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
} see you later!!!

