public class JDBCTest01 {public static void main(String[] args) {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;List<Student> studentList = new ArrayList<>(); // 钻石表达式(jdk7新特性。)try {// 1、注册驱动Class.forName("com.mysql.jdbc.Driver");// 2、获取连接String url = "jdbc:mysql://localhost:3306/wkcto";String user = "root";String password = "root";conn = DriverManager.getConnection(url, user, password);// 3、获取预编译的数据库操作对象String sql = "select id,name,birth from tbl_student";ps = conn.prepareStatement(sql);// 4、执行sql语句rs = ps.executeQuery();while(rs.next()){// 从结果集中取数据String id = rs.getString("id");String name = rs.getString("name");String birth = rs.getString("birth");// 将以上零散的数据封装成javabeanStudent student = new Student();student.setId(id);student.setName(name);student.setBirth(birth);// 将javabean放到容器当中studentList.add(student);}// 5、 处理查询结果集    } catch (Exception e) {e.printStackTrace();} finally {// 6、 释放资源if (rs != null){try {rs.close();} catch (SQLException e) {e.printStackTrace();}}if (ps != null){try {ps.close();} catch (SQLException e) {e.printStackTrace();}}if (conn != null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}// 拿着List集合去做展示。(View)for(Student s : studentList){System.out.println(s);}}}

JDBC编程的缺点
1、代码重复
以上代码中反复的从结果集中取数据,反复的调用对象的set方法给对象的属性赋值,这个过个完全可以使用反射机制替代,mybatis框架就是别人提前写好的java代码,这个mybatis 框架封装了JDBC代码,mybatis框架中使用反射机制,帮助我们自动创建了java对象,自动给java对象的属性赋值,以上的代码在mybatis中不需要编写了
2、sql语句的优化
JDBC开发中sql语句是编写在java程序当中的,sql语句不支持配置,可能后期需要调优,sql语句被修改的概率是很高的。在java程序中编写sql语句,后期修改SQL语句的时候,需要修改Java源代码,源代码的修改会导致重新编译、重新部署等操作。并且修改java源代码已经违背了开闭原则:(对修改关闭,对增加开放)
互联网分布式架构的项目,并发两很大,系统需要不断的优化,各方面优化,其中有一条非常重要的优化就是sql优化
第1章MyBatis 入门
框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种定义认为,框架是可被应用开发者定制的应用骨架。
对于程序员来说,框架是一套资源,这套资源中会包含Jar包、文档、还有些会包含源代码、代码示例等。这套资源从相关官网上可以下载。
1.1.1 MyBatis 的下载
  MyBatis 的可以在 github 官网下载:  
  https://github.com/mybatis/mybatis-3/releases

1.1.2 MyBatis 的 Jar 包
MyBatis 框架的解压目录中只有一个 Jar 包,它是 MyBatis 的核心 Jar 包。另外,还有个lib 目录,其中存放着 MyBatis 所依赖的 Jar 包。所以,使用 MyBatis,需要将其核心 Jar 包, 及 lib 下的所有 Jar 包导入。     
1.2 MyBatis 概述
 MyBatis 本是 apache 的一个开源项目 iBatis ,2010 年这个项目由 apache 迁移到了 google code
,并更名为 MyBatis。2013 年迁移到 Github。
  mybatis – MyBatis 3 | 简介
1.2.1 MyBatis 简介
MyBatis 是一个优秀的基于 Java 的持久层框架,它内部封装了 JDBC,使开发者只需关注SQL 语句本身,而不用再花费精力去处理诸如注册驱动、创建 Connection、配置 Statement等繁杂过程。Mybatis 通过xml 或注解的方式将要执行的各种语句statemen(statement、preparedStatement等)配置起来,并通过 Java对象和 Statement中SQL的动态参数进行映射生成最终执行的SQL语句,最后由MyBatis 框架执行 SQL并将结果映射成Java对象并返回。  
1、是一个持久层的框架,不是一个标准的ORM框架。
2、前身是ibatis ,在3.X时,更名为MyBatis。
3、MyBatis在java和sql之间提供更灵活的映射方案。
4、mybatis 可以将对数据表的操作(SQL)等直接剥离,写到xml配置文件,实现和java 代码的解耦。
5、mybatis 只负责sql,建库建表的工作由程序员员完成。
1.2.2 MyBatis 与 Hibernate
Hibernate 框架是提供了全面的数据库封装机制的“全自动”ORM(Object Relationship Mapping),即实现了 POJO 和数据库表之间的映射,以及 SQL 的自动生成和执行。
相对于此,MyBatis 只能算作是“半自动”ORM。其着力点,是在 POJO 类 与 SQL 语句之间的映射关系。也就是说,MyBatis 并不会为程序员自动生成 SQL 语句。具体的 SQL 需要程序员自己编写,然后通过 SQL 语句映射文件,将 SQL 所需的参数,以及返回的结果字段映射到指定 POJO。因此,MyBatis 成为了“全自动”ORM 的一种有益补充。
与 Hibernate 相比,MyBatis 具有以下几个特点:
(1)在 XML 文件中配置 SQL 语句,实现了 SQL 语句与代码的分离,给程序的维护带来了很大便利。
(2)因为需要程序员自己去编写SQL 语句,程序员可以结合数据库自身的特点灵活控制 SQL 语句,因此能够实现比 Hibernate 等全自动 ORM 框架更高的查询效率,能够完成复杂查询。
(3)简单,易于学习,易于使用,上手快。
1.2.3 MyBatis 体系结构
1.3 MyBatis 工作原理
  
   Object -Relational -Mapping 框架
 
1.4 第一个 MyBatis 程序(重点)
  需求:实现将 Student 信息写入到 DB 中
  
1.4.1 基本程序
  项目:01-primary
  
(1)导入 Jar 包
除了需要导入 MyBatis 的核心 Jar 包及依赖 Jar 包外,还需要导入 MySql 的驱动 Jar 包,JUnit 测试的 Jar 包。核心 Jar 包与依赖 Jar 包,均在 MyBatis 框架的解压目录下。
简单介绍一下log4j
log4j是专门用于输出日志,在java开发中,我们都使用log4j功能强大,可以满足各种输出日志需求,比如输出线程号、日期、各种数据,还可以对输出的日志级别进行控制Debug,Error…
(2) 定义实体类
实体类,就是一个普通的POJO类,类名建议和表名一致。因为使用原生态的sql语句查询结果还是要封装成对象,所以建议实体类的属性名称和表字段名保持一致。
注意,实体类的属性和成员变量的区别,属性是get和set方法名称去掉get或set后剩下的部分第一个字母从大写变小写后的字符串
id类型最好写成Integer 不写成int, Integer类型可以进行id!=null的判断

public class Student {private Integer id;private String name;  //name是成员变量private int age; //ages是成员变量private double score;public Student() {super();}public Student(String name, int age, double score) {super();this.name = name;this.age = age;this.score = score;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {  // getName方法名称去掉get,N变小写即name是属性                 return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public double getScore() {return score;}public void setScore(double score) {this.score = score;}@Overridepublic String toString() {return "Student [id=" + id + ", name=" + name + ", age=" + age+ ", score=" + score + "]";}
}  

(3) 在 DB 中生成表结构,即创建空表
  
  创建数据库 test,创建表 student ,可以使用Navicat for MySQL等工具
SET FOREIGN_KEY_CHECKS=0;


– Table structure for student


DROP TABLE IF EXISTS student;
CREATE TABLE student (
id int(5) NOT NULL AUTO_INCREMENT,
name varchar(20) DEFAULT NULL,
age int(3) DEFAULT NULL,
score double DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;


– Records of student


(上面的建表命令可以转储形成一个sql文件,这个文件复制到另外一台机器上可以运行后创建上面的sql文件,右击数据库名称—>选择“运行SQL文件”。数据库需要手工创建)

如果没有创建数据库,可以在sql文件的前面添加建数据库的命令:
create database test;
use test;
注意:由于后面要创建的 MyBatis 映射文件映射的是 SQL 语句,而非像 Hibernate 一样,是类到表,属性到字段的映射。所以,MyBatis 要求,在创建数据库表时,字段名要与属性名一致(当然,不一致时,还可通过 resultMap 解决,后面会讲)。  
(4) 定义 Dao 接口

  public interface IStudentDao {void insertStu(Student student);
}

(5) 定义映射文件
映射文件,简称为 mapper,主要完成 Dao 层中 SQL 语句的映射。具体映射的配置,后面会详细讲解。映射文件名随意,一般放在dao 包中。这里映射文件名称习惯定为 mapper.xml。映射文件的约束文件是 mybatis-3-mapper.dtd文件,在MyBatis的核心Jar 包的org.apache.ibatis.builder.xml 包中存放。当然,主配置文件的约束 dtd 文件mybatis-3-config.xml也在该位置存放。

在映射文件中添加约束,即配置文件头,可以从 MyBatis 框架中的文档 mybatis-3.3.0.pdf中找到:
在 pdf 中搜索“mybatis-3-mapper.dtd”关键字,即可找到映射文件的约束。

输入XML元素时候如果没有提示,可以参考基础2.1.6, mybatis-3-mapper.dtd和mybatis-3-config.dtd两个文件在mybatis-3.3.0\org\apache\ibatis\builder\xml目录下>

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

映射文件内容为:
注意,#{ }中写入的是 Student类的属性名。
对于 parameterType 属性,框架会自动根据用户执行的SqlSession 方法中的参数自动检测到,所以一般我们不用指定 parameterType 属性。一般写为如下形式:

<mapper namespace="test"><insert id="insertStudent">insert into student(name,age,score) values(#{name}, #{age}, #{score})</insert>
</mapper>

1、namespace :命名空间
2、insert:表示添加操作
3、id=“insertStudent” 表示接口的方法名
4、parameterType 表示该方法输入的参数类型,用来给Sql语言的占位符传值的,
javaBean给占位符传值的时候,程序员需要告诉mybatis,javabean的哪个属性传到哪个占位符
mybatis中的占位符不能使用?,必须使用#{},并且# {这里需要写Javabean 的属性名}
parameterType=“简单类型” ,如果是简单类型可以省略
简单类型有: 17个,8个基本数据类+8个包装类型+1个String类型
如果#{}只有一个,#{这里可以随便写}

(6) 定义主配置文件
在主配置文件中添加约束,即配置文件头,可以从 MyBatis 框架中的文档mybatis-3.3.0.pdf 中找到.在 pdf 中搜索“mybatis-3-config.dtd”关键字,即可找到映射文件的约束。主配置文件名也可以随意命名,例如本例定义为 mybatis.xml。文件名不固定的,位置放在src目录下。而对于标签中的 name 属性名称,需要从帮助文档中查找。先从帮助文档上复制一份,进行修改,建议复制后放到记事本再复制出来。

<?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="onlineEM"><environment id="onlineEM"><transactionManager type="JDBC"/> <!--事务--><!--配置数据源--><dataSource type="POOLED"> <!-- 数据库连接池 --><property name="driver" value="cn.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://127.0.0.1:3306/test/>  <!-- 127.0.0.1:3306可省略 --><property name="username" value="root"/><property name="password" value="111"/></dataSource>
</environment>
<environment id="testEM"><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url"  value="jdbc:mysql://127.0.0.1:3306/test"/><property name="username" value="root"/>< property name="password" value="111"/></dataSource></environment></environments><!-- 引入注册映射文件 --><mappers><mapper resource="cn/cslg/dao/mapper.xml"/></mappers></configuration>

可以配置多个,程序运行的时候,只使用用一个,default 指定
Element : configuration
Content Model : (properties?, settings?, typeAliases?, typeHandlers?, objectFactory?,
objectWrapperFactory?, reflectorFactory?, plugins?, environments?, databaseIdProvider?,
mappers?) ,?号表示小于等于1,最多有1个
Element : environments
Content Model : (environment+) +号表示大于等于1
Element : transactionManager
Content Model : (property*) * 号表示大于等于0
Element : environment
Content Model : (transactionManager, dataSource) ,逗号表示顺序
Content Model :如果只有一个元素,表示有且仅有一个元素
,数据库连接池可以提高程序访问数据库的效率
property配置了数据库连接的四要素,可以查看班助文档
xml文件中的注释可以用快捷键CRT+ALT+/,取消用CRT+ALT+
,resource的值可以复制,选中文件mapper.xml右击, 选Copy Qualified Name
(7) 定义 Dao 实现类

public class StudentDaoImpl implements IStudentDao {private SqlSession sqlSession;
@Override
public void insertStu(Student student) {try {// 1.加载主配置文件InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
// 2.创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3 创建sqlSession对象,java程序和数据库之间的会话,就像httpsession服务器和浏览器之间的会话sqlSession = sqlSessionFactory.openSession();
// 4.相关操作sqlSession.insert("insertStudent", student); //映射文件中的insertStudent如果名称相同,可以用名称空间区分 sqlSession.commit();//提交
} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();
} finally {if(sqlSession != null) {sqlSession.close();
}
}
}

(8)定义测试类

public class MyTest {private IStudentDao dao;@Beforepublic void before() {dao = new StudentDaoImpl();}@Testpublic void testInsert() {Student student = new Student("张三", 23, 93.5);dao.insertStu(student);}}

(9) 添加日志控制文件
MyBatis 使用Log4j 进行日志处理,而 Log4j2对其支持并不好,所以在 MyBatis 中需要将 log4j.properties 放入到项目的 src 目录下。

##define an appender named console
log4j.appender.console=org.apache.log4j.ConsoleAppender
#The Target value is System.out or System.err
log4j.appender.console.Target=System.out
#set the layout type of the apperder
log4j.appender.console.layout=org.apache.log4j.PatternLayout
#set the layout format pattern
log4j.appender.console.layout.ConversionPattern=[%-5p] %m%n
##define a logger
log4j. rootLogger=debug,console

若将日志级别设置为debug,则可以显示出所执行的 SQL语句、参数值、对DB的影响条数等信息。若将级别设置为 trace,则还可显示出查询出的每条记录的每个字段名及值。不过,需要注意的是,若日志对象使用根日志对象rootLogger,则会输出太多的信息。
在 MyBatis中,可以指定要输出日志的工作空间 namespace 的名字。此时,只会输出该namespace下执行的 SQL 的日志内容。例如:
log4j.logger.test=debug,console,这里的test就是namespace的名字
如果有多个映射配置文件,多个id值如果相同,sqlSession.insert(“insertStudent”, student);需要加上名称空间sqlSession.insert(“名称空间.insertStudent”, student);
1.4.2使用工具类
(1)创建工具类
项目:primary-2,在项目primary 基础上修改。
由于每一次执行 SqlSession 的方法,均需首先获取到该对象。SqlSession 对象的获取又相对比较繁琐,所以,可以将获取 SqlSession 对象定义为一个工具类方法。sqlSession 对象是通过 SqlSessionFactory对象创建的。由于 SqlSessionFactory 类为重量级对象(创建时候消耗的资源比较多),且没有可以修改的属性,是线程安全的,所以,可以将 SqlSessionFactory对象定义为单例的。

public class MyBatisUtils {private static SqlSessionFactory sqlSessionFactory;public static SqlSession getSqlSession() {try {InputStream is = Resources.getResourceAsStream("mybatis.xml");if (sqlSessionFactory == null) {sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);}return sqlSessionFactory.openSession();} catch (IOException e) {e.printStackTrace();}return null;}
}

(2) 修改 Dao 接口的实现类
该实现类使用 MyBatisUtil 工具类获取 SqlSession 对象。注意,由于这里没有异常需要处理,但SqlSession 必须要关闭,所以这里的代码必须要有 finally{}语句块,但无需 catch{ }代码块了。

public class StudentDaoImpl implements IStudentDao {private SqlSession sqlSession;@Overridepublic void insertStu(Student student) {try {sqlSession = MyBatisUtils.getSqlSession();sqlSession.insert("insertStudent", student);sqlSession.commit();} finally {if(sqlSession != null) {sqlSession.close();}}}
}

1.4.3 从属性文件中读取DB连接四要素
项目:primary-3,在项目 primary-2 基础上修改。
为了方便对数据库连接的管理,例如从MySQL数据库切换到别的数据库容易修改,只需要修改标签的 resource 属性值,并不是修改属性文件。DB 连接四要素数据一般都是存放在一个专门的属性文件中的。MyBatis 主配置文件需要从这个属性文件中读取这些数据。
(1) 定义属性文件
在 src 下定义属性文件 jdbc.properties。

jdbc.driver=cn.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/test
jdbc.user=root
jdbc.password=root

(2)修改主配置文件
对主配置文件,第一,需要注册属性文件。第二,需要从属性文件中通过key,将其 value读取出来

<configuration><!-- 注册DB连接四要素属性文件 --><properties resource="jdbc_mysql.properties"/><!-- 定义类型别名 --><typeAliases><!-- <typeAlias type="cn.cslg.beans.Student" alias="Student"/> --><!-- 将指定包中所有类的简单类名当作其别名 --><package name="cn.cslg.beans"/></typeAliases><!-- 配置运行环境 --><environments default="testEM"><environment id="testEM"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.user}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><!-- 注册映射文件 --><mappers><mapper resource="cn/cslg/dao/mapper.xml"/></mappers></configuration>

1.4.4 多个映射文件
在真正项目中,一般情况下会一个 Dao 接口对应一个映射文件。所以,一个项目中多个映射文件的情况会非常普遍。
项目:primary-4,在项目 primary-3 基础上修改。
(1) 新添加一个映射文件
将原来的映射文件直接复制一份,粘贴到相同目录中,并重命名,然后,在主配置文件中对其进行注册。此时,再运行相同的测试,会报错。因为可以匹配上的相同的 SQL 映射 id 出现了两个,系统不知应该执行哪一个。
(2) 修改任意一个映射文件
可以修改任意一个映射文件标签的 namespace 属性,将两个不同映射文件中的 SQL 映射,归入为不同的命名空间。
命名空间的作用是用于区分不同命名空间中的同名 SQL 映射的id。例如,将其中的一个namespace 修改为test2。
(3) 修改 Dao 实现类
在 Dao 实现类中使用时,需要给出具体使用的是哪个命名空间下的 SQL 映射语句。

 @Override
public void insertStu(Student student) {try {// 1.加载主配置文件InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");// 2.创建SqlSessionFactory对象SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);sqlSession = sqlSessionFactory.openSession();// 4.相关操作sqlSession.insert("test.insertStudent", student);sqlSession.cnmit();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {if(sqlSession != null) {sqlSession.close();}}
}      

在程序中,即使包含多个命名空间,而所使用的SQL 映射在这些命名空间中的 id 都是唯一的,那么,在使用时不使用命名空间作为前辍,而是直接使用SQL映射的 id,也是可以的。但不建议这样使用。  
1.5主配置文件详解
主配置文件名可以随意命名,其主要完成以下几个功能:
(1)注册存放 DB 连接四要素的属性文件
(2)注册实体类的全限定性类名的别名
(3)配置 MyBatis 运行环境,即数据源与事务管理器
(4)注册映射文件
(1)注册连接DB四要素的属性文件
F2 查看其父标签的描述信息可知,子标签应该是第一个子标签。

(2)指定实体类全限定性类名的别名 对于实体类的全限定性类名的别名指定方式,一般使用方式。这样做的好处是会将该包中所有实体类的简单类名指定为别名,写法简单方便。 使用标签和子标签,位置在标签后,标签前,例如 如果alias的值,例如指定为XXX,则在映射文件中使用,别名一般使用简单类名,例如,Student,该方式的好处是,可以指定别名为简单类名以外的其它名称。当然,弊端是,必须逐个指定,比较繁琐。

还可以通过package 标签指定别名,例如:

如果 在映射文件中的,parameterType属性可以省略

除了自定义的类型的别名外,MyBatis 还提供了内置的类型别名:
基本类型:
  
别名 类型 别名 类型
_int int _integer int
_short short _long long
_double double _float float
_byte byte _boolean boolean
  常用包装类型:
    
别名 类型 别名 类型
string String byte Byte
long Long short Short
int Integer integer Integer
double Double float Float
boolean Boolean date Date
object Object collection Collection
list List arraylist ArrayList
map Map hashmap HashMap
iterator Iterator

(3) 配置Mybatis运行环境
 A、标签
在中可以包含多个运行环境,但其 default 属性指定了当前Mybatis运行时选择使用的环境

 <!-- 配置运行环境 -->
<environments default="onlineEM"><environment id="onlineEM"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="cn.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://127.0.0.1:3306/test"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment><environment id="testEM"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="cn.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://127.0.0.1:3306/test"/><property name="username" value="root"/><property name="password" value="111"/></dataSource></environment>
</environments>

的 id 属性为当前定义的运行环境的名称,可以任意命名。该名称会作为的 default 属性的值出现。
  B、 标签
   

该标签用于指定 MyBatis 所使用的事务管理器。MyBatis 支持两种事务管理器类型:JDBC 与 MANAGED。
JDBC:使用 JDBC 的事务管理机制。即,通过 Connection 的 commit()方法提交,通过rollback()方法回滚。但默认情况下,MyBatis 将自动提交功能关闭了,改为了手动提交。即程序中需要显式的对事务进行提交或回滚。从日志的输出信息中可以看到。
MANAGED:由容器来管理事务的整个生命周期(如 Spring 容器)。
C、 标签
该标签用于配置 MyBatis 使用的数据源类型与数据库连接基本属性。常见有类型有:UNPOOLED、POOLED、JDNI 等。
UNPOOLED :不使用连接池。即每次请求,都会为其创建一个 DB 连接,使用完毕后,会马上将此连接关闭。
POOLED:使用数据库连接池来维护连接。
JNDI:数据源可以定义到应用的外部,通过 JNDI 容器获取数据库连接。

  <dataSource type="POOLED"><property name="driver" value="cn.mysql.jdbc.Driver"/><property name="url"  value="jdbc:mysql://127.0.0.1:3366/test"/><property name="username" value="root"/><property name="password" value="111"/>
</dataSource>

若要从属性文件中读取 DB 连接四要素信息,则使用如下方式:

<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource> 

例如属性文件的内容如下
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/test
jdbc.user=root
jdbc.password=root
(4)指定映射文件
  指定映射文件的方式有多种。但所有的方式,都是指定在标签中的。
A、指定映射文件

<!-- 注册映射文件 --><mappers><mapper resource="cn/cslg/dao/mapper.xml"/></mappers>

若映射文件有多个,则可使用如下形

<!-- 注册映射文件 --><mappers><mapper resource="cn/edu/cslg/dao/mapper.xml"/><mapper resource="cn/edu/cslg/dao/mapper2.xml"/></mappers>

B、指定映射文件(了解)

      <mappers><mapper url="file:///E:\IStudentDao.xml"/>
</mappers> 

该方式的好处是,可以将映射文件放在本地或网络的任意位置,通过其 url 地址即可直接访问。但通常映射文件是存放在当前应用中的,所以该方式不常用。  
C 、映射文件中的 namespace 属性值为 Dao 接口的全类名

该方式的使用,需要满足以下几个要求:
(1)映射文件名要与 Dao 接口名称相同
(2)映射文件要与接口在同一包中
(3)映射文件中的 namespace 属性值为 Dao 接口的全类名
D、指定映射文件
当映射文件较多时,也可以使用如下形式。其中 package 的 name 属性指定映射文件所存放的包。

<mappers><package name="com.abc.dao"/>
</mappers>

但,这种方式的使用需要满足以下几个条件:
  (1)dao 使用 mapper 动态代理实现(后面讲)
  (2)映射文件名要与 Dao 接口名称相同
  (3)映射文件要与接口在同一包中
  (4)映射文件中的 namespace 属性值为 Dao 接口的全类名
1.6 API 详解
1、执行这句sqlsession.commit() 为什么提交事务了?
2、执行inputStream 流为什么不用关闭?
3、执行sqlsession.close()方法就不用回滚了,为什么?
Dao 中需要通过 SqlSession 对象来操作 DB。而 SqlSession 对象的创建,需要其工厂对象SqlSessionFactory。SqlSessionFactory 对象,需要通过其构建器对象 SqlSessionFactoryBuilder 的 build()方法,在加载了主配置文件的输入流对象后创建。
  
(1) Resources 类
Resources 类,顾名思义就是资源,用于读取资源文件。其有很多方法通过加载并解析资源文件,返回不同类型的 IO 流对象。
(2)SqlSessionFactoryBuilder 类
SqlSessionFactory 的创建,需要使用 SqlSessionFactoryBuilder 对象的 build()方法。由于SqlSessionFactoryBuilder 对象在创建完工厂对象后,就完成了其历史使命,即可被销毁。所以,不需要引用,一般会将该 SqlSessionFactoryBuilder 对象创建为一个方法内的局部对象,方法结束,对象销毁。其被重载的 build()方法较多.
(3)SqlSessionFactory 接口
SqlSessionFactory 接口对象是一个重量级对象(系统开销大的对象),是线程安全的,所以一个应用只需要一个该对象即可。创建 SqlSession 需要使用 SqlSessionFactory 接口的openSession()方法。
openSession(true): 创建一个有自动提交功能的 SqlSession
openSession(false):创建一个非自动提交功能的 SqlSession,需手动提交
openSession():同 openSession(false)
(4)SqlSession 接口

SqlSession 接口实现类对象用于执行持久化操作。一个 SqlSession 对应着一次数据库会话,一次会话以 SqlSession 对象的创建开始,以 SqlSession 对象的关闭结束。
SqlSession 接口实现类对象是线程不安全的,所以每次数据库会话结束前,需要马上调用其close()方法,将其关闭。再次需要会话,再次创建。而在关闭时会判断当前的 SqlSession 是否被提交:若没有被提交,则会执行回滚后关闭;若已被提交,则直接将 SqlSession 关闭。所以,SqlSession 无需手工回滚。
SqlSession 接口常用的方法有:参考帮助文档
  
(5) 源码分析(重要)
  
A、输入流的关闭
  打开build方法

 public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {try {XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);return build(parser.parse());} catch (Exception e) {throw ExceptionFactory.wrapException("Error building SqlSession.", e);} finally {ErrorContext.instance().reset();try {inputStream.close();} catch (IOException e) {// Intentionally ignore. Prefer previous error.}}}

在输入流对象使用完毕后,不用手工进行流的关闭。因为在输入流被使用完毕后,
SqlSessionFactoryBuilder 对象的 build()方法会自动将输入流关闭。

B、 SqlSession 的创建
 SqlSession 对象的创建,需要使用 SqlSessionFactory 接口对象的 openSession()方法。

打开 openSession()方法的源码:
在org.apache.ibatis.session.defaults.DefaultSqlSessionFactory实现类里
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
继续跟进:

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {Transaction tx = null;
try {final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {closeTransaction(tx); // may have fetched a connection so lets call close()throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);} finally {ErrorContext.instance().reset();}
}

继续跟:
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}
   
从以上源码可以看到,无参的openSession()方法,将事务的自动提交直接赋值为 false。而所谓创建 SqlSession,就是加载了主配置文件,创建了一个执行器对象(将来用于执行映射文件中的 SQL 语句),初始化了一个表示DB 数据被修改的标志变量 dirty,关闭了事务的自动提交功能。
操作快捷键:ALT+ 箭头 返回

C、 增删改的执行
对于 SqlSession 的 insert()、delete()、update()方法,其底层均是调用执行了 update()方法。

  @Overridepublic int insert(String statement, Object parameter) {return update(statement, parameter);}@Overridepublic int update(String statement) {return update(statement, null);}@Overridepublic int update(String statement, Object parameter) {try {dirty = true;MappedStatement ms = configuration.getMappedStatement(statement);return executor.update(ms, wrapCollection(parameter));} catch (Exception e) {throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);} finally {ErrorContext.instance().reset();}}

从以上源码可知,无论执行增、删还是改,均是对数据进行修改,均将 dirty 变量设置为 true,且在获取到映射文件中指定 id 的 SQL 语句后,由执行器 executor 执行。
  
D、SqlSession 的提交 commit()

@Overridepublic void commit() {commit(false);}private boolean isCommitOrRollbackRequired(boolean force) {return (!autoCommit && dirty) || force;}由以上代码可知,isCommitOrRollbackRequired(force)方法的返回值为 true。继承跟踪executor 的 commit()方法:@Overridepublic void commit(boolean force) {try {executor.commit(isCommitOrRollbackRequired(force));dirty = false;} catch (Exception e) {throw ExceptionFactory.wrapException("Error committing transaction.  Cause: " + e, e);} finally {ErrorContext.instance().reset();}}@Overridepublic void commit(boolean required) throws SQLException {if (closed) {throw new ExecutorException("Cannot commit, transaction is already closed");}clearLocalCache();flushStatements();if (required) {transaction.commit();//事务提交了}}

ALT+ 箭头返回

E、 SqlSession 的关闭
  
继承跟踪executor 的 close()方法:

@Override
public void close() {try {executor.close(isCommitOrRollbackRequired(false));
dirty = false;//提交后 dirty变成false
} finally {ErrorContext.instance().reset();
}
}

再跟踪 Executor 接口的 BaseExecutor 类的 close()方法:

@Override
public void close(boolean forceRollback) {try {try {rollback(forceRollback);
} finally {if (transaction != null) {transaction.close();
}
}
} catch (SQLException e) {// Ignore.  There's nothing that can be done at this point.
log.warn("Unexpected exception on closing transaction.  Cause: " + e);
} finally {transaction = null;
deferredLoads = null;
localCache = null;
localOutputParameterCache = null;
closed = true;
}
}@Overridepublic void rollback(boolean required) throws SQLException {if (!closed) {try {clearLocalCache();flushStatements(true);} finally {if (required) {transaction.rollback();}}}}

如果没提交,dirty=true; isCommitOrRollbackRequired(false)为true, if (required) {}语句会执行,所以回滚执行了,数据写不到数据库。
如果提交了, dirty=false; isCommitOrRollbackRequired(false)为false, if (required) {…}里语句不执行执行,所以不执行回滚。

MyBatis 框架技术笔记相关推荐

  1. mybatis框架--学习笔记(下)

    上篇:mybatis框架--学习笔记(上):https://blog.csdn.net/a745233700/article/details/81034021 8.高级映射: (1)一对一查询: ①使 ...

  2. mybatis框架--学习笔记(上)

    使用JDBC操作数据库的问题总结: (1)数据库连接,使用时创建,不使用时立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响数据库性能. 设想:使用数据库连接池管理数据库连接. (2) ...

  3. [Spring+SpringMVC+Mybatis]框架学习笔记(四):Spring实现AOP

    上一章:[Spring+SpringMVC+Mybatis]框架学习笔记(三):Spring实现JDBC 下一章:[Spring+SpringMVC+Mybatis]框架学习笔记(五):SpringA ...

  4. 2021年3月8日:MyBatis框架学习笔记02:利用MyBatis实现CRUD操作

    MyBatis框架学习笔记02:利用MyBatis实现CRUD操作 在第一节课中我们在UserMapper.xml里定义了两个查询语句:findById和findAll,对应的在UserMapper接 ...

  5. MyBatis框架学习笔记(1)——B站动力节点

    文章目录 001- 框架概述 1.1 软件开发常用结构 1.2 框架是什么 1.3 回顾JDBC编程 1.4 MyBatis框架概述 002- MyBatis框架快速入门 2.1 入门案例 2.2 M ...

  6. MyBatis框架学习笔记02:使用MyBatis实现CRUD操作

    文章目录 Ⅰ.查询表记录 (Ⅰ).在映射器配置文件里引入结果映射元素 (Ⅱ).添加按姓名查询用户记录功能 1).在UserMapper.xml里添加映射语句 - findByName 2).在User ...

  7. MyBatis框架学习笔记01:初生牛犊

    文章目录 1. 什么是MyBatis 创建数据库 演示MyBatis基本使用 1.创建Maven项目 创建实体类 创建用户实体类关系映射配置文件 创建测试类 完成测试 1. 什么是MyBatis My ...

  8. MyBatis框架学习笔记(3)——B站动力节点

    文章目录 (0)介绍 (1)返回主键的标签 (2)UUID的概念 (3)update时< set >标签的使用 (4)表与表的关联关系 一对多关联 多对一关联 一对一关联 多对多关联 (5 ...

  9. MyBatis框架学习笔记04:利用MyBatis实现条件查询

    文章目录 一.查询需求 二.打开MyBatisDemo项目 三.对学生表实现条件查询 (一)创建学生映射器配置文件 (二)在MyBatis配置文件里注册学生映射器配置文件 (三)创建学生映射器接口 ( ...

最新文章

  1. php+mysql+pdo连接数据库
  2. java安卓获取mac_android开发分享以编程方式获取Android设备的MAC
  3. 一步一步部署SSIS包图解教程1
  4. n76e885_新唐N76E003,N76E616烧录,调试各种问题集【坑集】
  5. python rpa库_Automagica python RPA库实践
  6. 编译程序 解释程序
  7. 漫画:唐玄奘教你横扫 AVL 树面试题无敌手!
  8. CVPR学习(三):CVPR2019-各个方向
  9. flask专题-小说网站开发四(完结)
  10. vmware 设置ip
  11. Linux/Centos7搭建饥荒服务器教程
  12. 如何从RNN起步,一步一步通俗理解LSTM
  13. iOS地图定位系统语言为英文时,返回中文位置信息
  14. 网络电话语音通话的android实现
  15. 2022年各省春晚收视率如何?地图分析帮你清楚展现
  16. JAVA计算机毕业设计快递物流管理部署+源码+数据库+系统+lw文档
  17. 信管家显示连接服务器失败,信管家交易软件,条件单设置方法
  18. 常见职位的英文简称_揭秘 | 90%的留学生会犯的10大英文简历致命错误...
  19. 科技公司保密协议范本
  20. python中update是啥意思_python中update的基本使用

热门文章

  1. 将123倒转 c语言,中国航信杯C语言程序设计答案解析版.doc
  2. 杨百万:股票投资者修养
  3. 关于PN532 读取二代证UUID____记录自己亲自实验成功!!!
  4. 【微信群助手机器人】好不好用?可以实现哪些功能?
  5. 【python】print函数的用法示例与讲解
  6. OSChina 周五乱弹 ——什么情况下两个人之间的距离能成为负数
  7. 天天天蓝——第五章 四月的春天
  8. 因果模型五:用因果的思想优化风控模型——因果正则化评分卡模型
  9. 嵌入式linux--电子相册
  10. oppo怎么打开科学计算机,OPPOr11的计算器怎么打开