resources 目录中的文件 等同于放在类的根路径下
1.引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.powernode</groupId>
<artifactId>mybatis-001-introduction</artifactId>
<version>1.0-SNAPSHOT</version>
<!--打包方式-->
<packaging>jar</packaging>
<dependencies>
<!-- mybatis依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<!--mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<!-- junit依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!--logback实现-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
</dependencies>
</project>
2.从XML中构建SqlSessionFactory
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。
从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。 但也可以使用任意的输入流(InputStream)实例,比如用文件路径字符串或 file:// URL 构造的输入流。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,使得从类路径或其它位置加载资源文件更加容易。
在resources根目录下新建mybatis-config.xml配置文件(可以参考mybatis手册拷贝)
XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)。
<?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="development">
<environment id="development">
<!--事务管理器 JDBC或 MANAGED-->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--JDBC连接Mysql5需用com.mysql.jdbc.Driver -->
<!--JDBC连接Mysql6需用com.mysql.cj.jdbc.Driver,同时需要指定时区serverTimezone-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--&需要使用 & 代替-->
<!--jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false-->
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--执行XxxMapper.xmL文件的路径-->
<!--resource属性自动会从类的根路径下开始查找资源-->
<mapper resource="CarMapper.xml"/>
</mappers>
</configuration>
dtd 文档类型约束
注意 XML 头部的声明,它用来验证 XML 文档的正确性。environment 元素体中包含了事务管理和连接池的配置。mappers 元素则包含了一组映射器(mapper),这些映射器的 XML 映射文件包含了 SQL 代码和映射定义信息。
configuration:根标签,表示配置信息。
environments:环境(多个),以“s”结尾表示复数,也就是说mybatis的环境可以配置多个数据
源。
default属性:表示默认使用的是哪个环境,default后面填写的是environment的id。
default的值只需要和environment的id值一致即可。
environment:具体的环境配置(主要包括:事务管理器的配置 + 数据源的配置)
id:给当前环境一个唯一标识,该标识用在environments的default后面,用来指定默认环境的
选择。
transactionManager:配置事务管理器
type属性:指定事务管理器具体使用什么方式,可选值包括两个
JDBC:使用JDBC原生的事务管理机制。底层原理:事务开启
conn.setAutoCommit(false); ...处理业务...事务提交conn.commit();
MANAGED:交给其它容器来管理事务,比如Spring 、WebLogic、JBOSS等。
如果没有管理事务的容器,则没有事务。没有事务的含义:只要执行一条DML语句
,则提交一次。
dataSource:指定数据源
type属性:用来指定具体使用的数据库连接池的策略,可选值包括三个
UNPOOLED:采用传统的获取连接的方式,虽然也实现Javax.sql.DataSource接口,但是并没有使用池的思想。
property可以是:driver 这是 JDBC 驱动的 Java 类全限定名。
url 这是数据库的 JDBC URL 地址。
username 登录数据库的用户名。
password 登录数据库的密码。
defaultTransactionIsolationLevel 默认的连接事务隔离级别。
defaultNetworkTimeout 等待数据库操作完成的默认网络超时时间(单位:毫秒)
POOLED:采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实
现。
property可以是(除了包含UNPOOLED中之外):
poolMaximumActiveConnections 在任意时间可存在的活动(正在使用)连接数
量,默认值:10
poolMaximumIdleConnections 任意时间可能存在的空闲连接数。
其它....
JNDI:采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到
DataSource是不一样。如果不是web或者maven的war工程,JNDI是不能使用的。
property可以是(最多只包含以下两个属性):
initial_context 这个属性用来在 InitialContext 中寻找上下文(即,
initialContext.lookup(initial_context))这是个可选属性,如果忽略,那么将会直接从InitialContext 中寻找 data_source 属性。
data_source 这是引用数据源实例位置的上下文路径。提供了 initial_context 配置时会
在其返回的上下文中进行查找,没有提供时则直接在 InitialContext 中查找。
mappers:在mappers标签中可以配置多个sql映射文件的路径。
mapper:配置某个sql映射文件的路径
resource属性:使用相对于类路径的资源引用方式
url属性:使用完全限定资源定位符(URL)方式
注意1:mybatis核心配置文件的文件名不一定是mybatis-config.xml,可以是其它名字。
注意2:mybatis核心配置文件存放的位置也可以随意。这里选择放在resources根下,相当于放到了类的根路径下。
3.mybatis中有两个主要的配置文件
其中一个是:mybatis-config.xml,这是核心配置文件,主要配置连接数据库的信息等。(一个)
另一个是:XXXxMapper.xml,这个文件是专门用来编写SOL语句的配置文件(一个表一个)
t_user表,一般会对应一个userMapper.xml
t_student表,一般会对应一个StudentMapper.xmL
4.编写XxxxMapper.xml文件
在这个配置文件当中编写SQL语句。
这个文件名也不是固定的,放的位置也不是固定,我们这里给它起个名字,叫做CarMapper.xml
把它暂时放到类的根路径下。
<?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="org.mybatis.example.BlogMapper">
<!--insert语句id是这条SQL语句的唯一标识。这个id就代表了这条SQL语句-->
<insert id="insertCar">
insert into t_car(id,car_num,brand,guide_price,produce_time,car_type)
values(null ,'1003','丰田霸道',30.0,'2000-10-11','燃油车')
</insert>
<!--<delete id=""></delete>-->
<!--<update id=""></update>-->
<!--<select id=""></select>-->
</mapper>
5.在mybatis-config.xml文件中指定XxxxMapper.xml文件的路径:
<mappers>
<!--执行XxxMapper.xmL文件的路径-->
<!--resource属性自动会从类的根路径下开始查找资源-->
<mapper resource="CarMapper.xml"/>
</mappers>
6.编写MyBatis程序。
(使用mybatis的类库,编写mybatis程序,连接数据库,做增删改查就行了。)
在MyBatis当中,负责执行SQL语句的那个对象叫做什么呢?
SqlSession
SqlSession是专门用来执行SQL语句的,是一个Java程序和数据库之间的一次会话。
要想获取SqlSession对象,需要先获取SqlSessionFactory对象,通过SqlSessionFactory工厂来生产SqlSession对象。
怎么获取SqlSessionFactory对象呢?
需要首先获取SqlSessionFactoryBuilder对象。
通过SqlSessionFactoryBuilder对象的build方法,来获取一个SqlSessionFactory对象。
mybatis的核心对象包括:
SqlSessionFactoryBuilder
SqlSessionFactory
SqlSession
SqlSessionFactoryBuilder --> SqlSessionFactory --> SqlSession
package com.powernode.mybatis.test;
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.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class MyBatisIntroductionTest {
public static void main(String[] args) throws IOException {
// 1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 2. 创建SqlSessionFactory对象
// 这只是一个输入流,可以自己new
//InputStream is = new FileInputStream("D:/mybatis-config.xml");
//或者使用mybatis提供的工具类 Resources.getResourcesAsStream
// 默认从类的根路径下查找资源
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
// 3. 创建SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4. 执行sql
int count = sqlSession.insert("insertCar");
System.out.println("插入几条数据:" + count);
// 5. 提交(mybatis默认采用的事务管理器是JDBC,默认是不提交的,需要手动提交。)
sqlSession.commit();
// 6. 关闭资源(只关闭是不会提交的)
sqlSession.close();
}
}
完整的程序应该是
package com.powernode.mybatis.test;
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;
/**
* 采用正规的方式 写1个完整版的MyBatis程序。
* @author
* @version
* @since
*/
public class MyBatisCompleteTest {
public static void main(String[] args) {
SqlSession sqlSession = null;
try {
// 1.创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 2.创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder
.build(Resources.getResourceAsStream("mybatis-config.xml"));
// 3.创建SqlSession对象
sqlSession = sqlSessionFactory.openSession();
// 4.执行SQL
int count = sqlSession.insert("insertCar");
System.out.println("更新了几条记录:" + count);
// 5.提交
sqlSession.commit();
} catch (Exception e) {
// 回滚
if (sqlSession != null) {
sqlSession.rollback();
}
e.printStackTrace();
} finally {
// 6.关闭
if (sqlSession != null) {
sqlSession.close();
}
}
}
}
7.关于第一个程序的小细节
* mybatis中sql语句的结尾";"可以省略。
* Resources.getResourceAsStream
小技巧:以后凡是遇到resource这个单词,大部分情况下,这种加载资源的方式就是从类的根路径下开始加载。(开始查找)
优点:采用这种方式,从类路径当中加载资源,项目的移植性很强。项目从windows移植到linux,代码不需要修改,因为这个资源文件一直都在类路径当中。
* InputStream is = new FileInputStream("d:\\mybatis-config.xml");
采用这种方式也可以。
缺点:可移植性太差,程序不够健壮。可能会移植到其他的操作系统当中。导致以上路径无效,还需要修改java代码中的路径。这样违背了OCP原则。
* 已经验证了:
mybatis核心配置文件的名字,不一定是:mybatis-config.xml。可以是其它名字。
mybatis核心配置文件存放的路径,也不一定是在类的根路径下。可以放到其它位置。但为了项目的移植性,健壮性,最好将这个配置文件放到类路径下面。
* InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("mybatis-config.xml");
ClassLoader.getSystemClassLoader() 获取系统的类加载器。
系统类加载器有一个方法叫做:getResourceAsStream
它就是从类路径当中加载资源的。
通过源代码分析发现:
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
底层的源代码其实就是:
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("mybatis-config.xml");
* CarMapper.xml文件的名字是固定的吗?CarMapper.xml文件的路径是固定的吗?
都不是固定的。
<mapper resource="CarMapper.xml"/> resource属性:这种方式是从类路径当中加载资源。
<mapper url="file:///d:/CarMapper.xml"/> url属性:这种方式是从绝对路径当中加载资源。
8.关于mybatis的事务管理机制。(深度剖析)
* 在mybatis-config.xml文件中,可以通过以下的配置进行mybatis的事务管理
<transactionManager type="JDBC"/>
* type属性的值包括两个:
JDBC(jdbc)
MANAGED(managed)
type后面的值,只有以上两个值可选,不区分大小写。
* 在mybatis中提供了两种事务管理机制:
第一种:JDBC事务管理器
第二种:MANAGED事务管理器
* JDBC事务管理器:
mybatis框架自己管理事务,自己采用原生的JDBC代码去管理事务:
conn.setAutoCommit(false); 开启事务。
....业务处理...
conn.commit(); 手动提交事务
使用JDBC事务管理器的话,底层创建的事务管理器对象:JdbcTransaction对象。
如果你编写的代码是下面的代码:
SqlSession sqlSession = sqlSessionFactory.openSession(true);
表示没有开启事务。因为这种方式压根不会执行:conn.setAutoCommit(false);
在JDBC事务中,没有执行conn.setAutoCommit(false);那么autoCommit就是true。
如果autoCommit是true,就表示没有开启事务。只要执行任意一条DML语句就提交一次。
* MANAGED事务管理器:
mybatis不再负责事务的管理了。事务管理交给其它容器来负责。例如:spring。
我不管事务了,你来负责吧。
对于我们当前的单纯的只有mybatis的情况下,如果配置为:MANAGED
那么事务这块是没人管的。没有人管理事务表示事务压根没有开启。
没有人管理事务就是没有事务。
* JDBC中的事务:
如果你没有在JDBC代码中执行:conn.setAutoCommit(false);的话,默认的autoCommit是true。
* 重点:
以后注意了,只要你的autoCommit是true,就表示没有开启事务。
只有你的autoCommit是false的时候,就表示开启了事务。
9.引入Junit
JUnit是专门做单元测试的组件。
在实际开发中,单元测试一般是由我们Java程序员来完成的。
我们要对我们自己写的每一个业务方法负责任,要保证每个业务方法在进行测试的时候都能通
过。
测试的过程中涉及到两个概念:
期望值
实际值
期望值和实际值相同表示测试通过,期望值和实际值不同则单元测试执行时会报错。
这里引入JUnit是为了代替main方法。
引入依赖
<!-- junit依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
第二步:编写单元测试类【测试用例】,测试用例中每一个测试方法上使用@Test注解进行标注。
测试用例的名字以及每个测试方法的定义都是有规范的:
测试用例的名字:XxxTest
测试方法声明格式:public void test业务方法名(){}
package com.powernode.junit.service;
import org.junit.Assert;
import org.junit.Test;
/**
* @author wyj
* @version 1.0
* @since 1.0
*/
public class MathServiceTest {
// 单元测试方法写多少个。
// 一般是一个业务方法对应一个测试方式。
// 测试方法的规范: public void testXxxx(){}
// 测试方法的方法名:以test开始。假设测试的方法是sum,这个测试方法名:testSum
// @Test注解非常重要,被这个注解标注的方法就是一个单元测试方法。
@Test
public void testSum(){
// 单元测试中有两个重要的概念:
// 一个是:实际值(被测试的业务方法的真正执行结果)
// 一个是:期望值(执行了这个业务方法之后,你期望的执行结果是多少)
MathService mathService = new MathService();
// 获取实际值
int actual = mathService.sum(1, 2);
// 期望值
//int expected = 3;
int expected = 3;
// 加断言进行测试
Assert.assertEquals(expected, actual);
}
@Test
public void testSub(){
MathService mathService = new MathService();
// 实际值
int actual = mathService.sub(10, 5);
// 期望值
int expected = 5;
// 添加断言机制
Assert.assertEquals(expected, actual);
}
}
10. 关于mybatis集成日志组件。让我们调试起来更加方便。
* mybatis常见的集成的日志组件有哪些呢?
SLF4J(沙拉风):沙拉风是一个日志标准,其中有一个框架叫做logback,它实现了沙拉风规范。
LOG4J
LOG4J2
STDOUT_LOGGING
logback
....
注意:log4j log4j2 logback都是同一个作者开发的。
* 其中STDOUT_LOGGING是标准日志,mybatis已经实现了这种标准日志。mybatis框架本身已经实现了这种标准。
只要开启即可。怎么开启呢?在mybatis-config.xml文件中使用settings标签进行配置开启。
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
这个标签在编写的时候要注意,它应该出现在environments标签之前。注意顺序。当然,不需要记忆这个顺序。
因为有dtd文件进行约束呢。我们只要参考dtd约束即可。
这种实现也是可以的,可以看到一些信息,比如:连接对象什么时候创建,什么时候关闭,sql语句是怎样的。
但是没有详细的日期,线程名字,等。如果你想使用更加丰富的配置,可以集成第三方的log组件。
* 集成logback日志框架。
logback日志框架实现了slf4j标准。(沙拉风:日志门面。日志标准。)
第一步:引入logback的依赖。
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
第二步:引入logback所必须的xml配置文件。
这个配置文件的名字必须叫做:logback.xml或者logback-test.xml,不能是其它的名字。
这个配置文件必须放到类的根路径下。不能是其他位置。
主要配置日志输出相关的级别以及日志具体的格式。
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址-->
<property name="LOG_HOME" value="/home"/>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/TestWeb.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5
个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>100MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!--mybatis log configure-->
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
<!--日志输出级别,logback日志级别包括五个 TRACE< DEBUG< INFO< WARN< ERROR -->
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root>
</configuration>