Mybatis学习笔记_1、初识Mybatis

简介

什么是 MyBatis?

MyBatis的前身是iBATIS,是Clinton Begin在2001年发起的一个开源项目,最初侧重于密码软件的开发,后来发展成为一款基于Java的持久层框架.2004年,Clinton将iBATIS的名字和源码捐赠给了Apache软件基金会.2010年,核心开发团队决定离开Apache软件基金会,并且将iBATIS该名为MyBatis.
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

MyBatis官网:MyBatis官网

MyBatis jar下载地址:

https://github.com/mybatis/mybatis-3/releases

MyBatis 工作原理

1. 流程图 :

MyBatis框架执行流程图如下所示

在这里插入图片描述

2.流程介绍

从MyBatis框架执行流程图中可得知,MyBatis框架在操作数据库时,大体经过了8个步骤.

  1. 读取MyBatis配置文件mybatis-config.xml.其作为MyBatis的全局配置文件,配置了MyBatis的运行环境等信息,其中主要内容是获取数据库连接.
  2. 加载映射配置文件Mapper.xml.既SQL映射文件,该文件配置了操作数据库的SQL语句,需要在mybatis-config.xml中加载才能执行.mybatis-config.xml可以加载多个配置文件,每个配置文件对应数据库中的一张表.
  3. 构建会话工厂.通过MyBatis的环境等配置信息构建会话工厂SqlSessionFactory.
  4. 创建SqlSession对象.由会话工厂创建SqlSession对象,该对象中包含了执行SQL的所有方法.
  5. MyBatis底层定义了一个Executor接口来操作数据库,它会根据SqlSession传递的参数动态地生成需要执行的SQL语句,同时负责查询缓存的维护.
  6. 在Executor接口的执行方法中,包含一个MappedStatement类型的参数,该参数是对映射信息的封装,用于存储要映射的SQL语句的id,参数等… Mapper.xml文件中一个SQL对应一个MappedStatement对象,SQL的id既是MappedStatement的id.
  7. 输入参数映射,其过程类似于JDBC编程中对preparedStatement对象设置参数的过程.
  8. 输出参数映射,其过程类似于JDBC编程中对结果的解析处理过程.

MyBatis 入门

1.构建 SqlSessionFactory

1.1从 XML 中构建 SqlSessionFactory

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。
从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。 但也可以使用任意的输入流(InputStream)实例,比如用文件路径字符串或 file:// URL 构造的输入流。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,使得从类路径或其它位置加载资源文件更加容易。

String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

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">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

在本学习内容中,主要从 XML 中构建 SqlSessionFactory。

1.2不使用 XML 构建 SqlSessionFactory

如果你更愿意直接从 Java 代码而不是 XML 文件中创建配置,或者想要创建你自己的配置建造器,MyBatis 也提供了完整的配置类,提供了所有与 XML 文件等价的配置项。

DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

注意该例中,configuration 添加了一个映射器类(mapper class)。映射器类是 Java 类,它们包含 SQL 映射注解从而避免依赖 XML 文件。不过,由于 Java 注解的一些限制以及某些 MyBatis 映射的复杂性,要使用大多数高级映射(比如:嵌套联合映射),仍然需要使用 XML 配置。有鉴于此,如果存在一个同名 XML 配置文件,MyBatis 会自动查找并加载它(在这个例子中,基于类路径和 BlogMapper.class 的类名,会加载 BlogMapper.xml)

2.从 SqlSessionFactory 中获取 SqlSession

既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。例如:

try (SqlSession session = sqlSessionFactory.openSession()) {
  Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
}

诚然,这种方式能够正常工作,对使用旧版本 MyBatis 的用户来说也比较熟悉。但现在有了一种更简洁的方式——使用和指定语句的参数和返回值相匹配的接口(比如 BlogMapper.class),现在你的代码不仅更清晰,更加类型安全,还不用担心可能出错的字符串字面值以及强制类型转换。

例如:

try (SqlSession session = sqlSessionFactory.openSession()) {
  BlogMapper mapper = session.getMapper(BlogMapper.class);
  Blog blog = mapper.selectBlog(101);
}

3.探究已映射的 SQL 语句

这里给出一个基于 XML 映射语句的示例,它应该可以满足上个示例中 SqlSession 的调用。

<?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">
  <select id="selectBlog" resultType="Blog">
    select * from Blog where id = #{id}
  </select>
</mapper>

为了这个简单的例子,我们似乎写了不少配置,但其实并不多。在一个 XML 映射文件中,可以定义无数个映射语句,这样一来,XML 头部和文档类型声明部分就显得微不足道了。文档的其它部分很直白,容易理解。 它在命名空间 “org.mybatis.example.BlogMapper” 中定义了一个名为 “selectBlog” 的映射语句,这样你就可以用全限定名 “org.mybatis.example.BlogMapper.selectBlog” 来调用映射语句了,就像上面例子中那样:

Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);

你可能会注意到,这种方式和用全限定名调用 Java 对象的方法类似。这样,该命名就可以直接映射到在命名空间中同名的映射器类,并将已映射的 select 语句匹配到对应名称、参数和返回类型的方法。因此你就可以像上面那样,不费吹灰之力地在对应的映射器接口调用方法,就像下面这样:

BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);

第二种方法有很多优势,首先它不依赖于字符串字面值,会更安全一点;其次,如果你的 IDE 有代码补全功能,那么代码补全可以帮你快速选择到映射好的 SQL 语句。

4.作用域(Scope)和生命周期

依赖注入框架可以创建线程安全的、基于事务的 SqlSession 和映射器,并将它们直接注入到你的 bean 中,因此可以直接忽略它们的生命周期。

4.1SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。

4.2SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式

4.3SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。 下面的示例就是一个确保 SqlSession 关闭的标准模式:

try (SqlSession session = sqlSessionFactory.openSession()) {
  // 你的应用逻辑代码
}

在所有代码中都遵循这种使用模式,可以保证所有数据库资源都能被正确地关闭。

4.4映射器实例

映射器是一些绑定映射语句的接口。映射器接口的实例是从 SqlSession 中获得的。虽然从技术层面上来讲,任何映射器实例的最大作用域与请求它们的 SqlSession 相同。但方法作用域才是映射器实例的最合适的作用域。 也就是说,映射器实例应该在调用它们的方法中被获取,使用完毕之后即可丢弃。 映射器实例并不需要被显式地关闭。尽管在整个请求作用域保留映射器实例不会有什么问题,但是你很快会发现,在这个作用域上管理太多像 SqlSession 的资源会让你忙不过来。 因此,最好将映射器放在方法作用域内。就像下面的例子一样:

try (SqlSession session = sqlSessionFactory.openSession()) {
  BlogMapper mapper = session.getMapper(BlogMapper.class);
  // 你的应用逻辑代码
}

MyBatis 入门程序

准备工作

导入jar包
在这里插入图片描述

在这里把最终的文件目录展示,以免文件放的位置不同造成没必要的困扰。
在这里插入图片描述

1. 新建一个数据库

简单的创建两张表:t_country & t_user
在这里插入图片描述
在这里插入图片描述
代码部分:

#新建数据库db_ssm_mybatis
CREATE DATABASE
IF
	NOT EXISTS db_ssm_mybatis DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
USE db_ssm_mybatis;
#建表
#CREATE TABLE IF NOT EXISTS name(col_name,col_type)DEFAULT CHARSET=utf8mb4;
#国家表
DROP TABLE
IF
	EXISTS t_country;
CREATE TABLE
IF
	NOT EXISTS t_country (
	c_id INT NOT NULL PRIMARY KEY auto_increment COMMENT '国家ID',
	c_countryname VARCHAR ( 18 ) NOT NULL COMMENT '国家名称' 
	) ENGINE = INNODB AUTO_INCREMENT = 6 DEFAULT CHARSET = utf8mb4;
#用户表
DROP TABLE
IF
	EXISTS t_user;
CREATE TABLE
IF
	NOT EXISTS t_user (
	u_id INT NOT NULL PRIMARY KEY auto_increment COMMENT '用户ID',
	u_username VARCHAR ( 18 ) NOT NULL COMMENT '用户名',
	u_password VARCHAR ( 18 ) NOT NULL COMMENT '用户密码',
	u_gender INT NOT NULL COMMENT '用户性别',
#(0男,1女)
	u_cid INT NOT NULL COMMENT '用户国家ID',
	FOREIGN KEY ( u_cid ) REFERENCES t_country ( c_id ) ON DELETE NO action ON UPDATE NO action #外键
	
	) ENGINE = INNODB AUTO_INCREMENT = 6 DEFAULT CHARSET = utf8mb4;
#插入一些数据
INSERT INTO t_country ( c_id, c_countryname )
VALUES
	( 1, '中国' ),
	( 2, '法国' ),
	( 3, '美国' ),
	( 4, '英国' ),
	( 5, '俄罗斯' );
INSERT INTO t_user ( u_id, u_username, u_password, u_gender, u_cid )
VALUES
	( 1, '老王', '12345', 0, 1 ),
	( 2, '王五', '123', 1, 3 ),
	( 3, '张三', '123', 0, 2 ),
	( 4, '李四', '321', 1, 1 ),
	( 5, '王八', '3232', 0, 4 ),
	( 6, '李白', '666', 0, 5 );
SELECT
	* 
FROM
	t_country;
SELECT
	* 
FROM
t_user;

2.Java bean

根据数据库表写一个简单的Java bean

package pers.goodwin.mybatis.bean;

/**
 * @author goodwin
 *
 */
public class User {
	private Integer u_id;
	private String u_username;
	private String u_password;
	private Integer u_gender;
	private Integer u_cid;
	public Integer getU_id() {
		return u_id;
	}
	public void setU_id(Integer u_id) {
		this.u_id = u_id;
	}
	public String getU_username() {
		return u_username;
	}
	public void setU_username(String u_username) {
		this.u_username = u_username;
	}
	public String getU_password() {
		return u_password;
	}
	public void setU_password(String u_password) {
		this.u_password = u_password;
	}
	public Integer getU_gender() {
		return u_gender;
	}
	public void setU_gender(Integer u_gender) {
		this.u_gender = u_gender;
	}
	public Integer getU_cid() {
		return u_cid;
	}
	public void setU_cid(Integer u_cid) {
		this.u_cid = u_cid;
	}
	@Override
	public String toString() {
		return "User [u_id=" + u_id + ", u_username=" + u_username + ", u_password=" + u_password + ", u_gender="
				+ u_gender + ", u_cid=" + u_cid + "]";
	}
}

顺便把另一个表对应的bean写了

package pers.goodwin.mybatis.bean;

/**
 * @author goodwin
 *
 */
public class Country {
	private Integer c_id;
	private String c_countryname;
	public Integer getC_id() {
		return c_id;
	}
	public void setC_id(Integer c_id) {
		this.c_id = c_id;
	}
	public String getC_countryname() {
		return c_countryname;
	}
	public void setC_countryname(String c_countryname) {
		this.c_countryname = c_countryname;
	}
	@Override
	public String toString() {
		return "Country [c_id=" + c_id + ", c_countryname=" + c_countryname + "]";
	}
}

3.配置数据库配置信息文件

db.properties

jdbc.driver = com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db_ssm_mybatis?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
jdbc.username=root
jdbc.password=123456

4.配置MyBatis核心配置文件:sqlMapConfig.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>
	<!-- 读取数据库配置文件 -->
	<properties resource="db.properties" />
	<!-- 配置环境-默认环境id为MySQL -->
	<environments default="MySQL">
		<environment id="MySQL">
			<!-- 使用JDBC事务管理 -->
			<transactionManager type="JDBC" />
			<!-- 数据库连接池 -->
			<dataSource type="POOLED">
				<property name="driver" value="${jdbc.driver}" />
				<property name="url" value="${jdbc.url}" />
				<property name="username" value="${jdbc.username}" />
				<property name="password" value="${jdbc.password}" />
			</dataSource>
		</environment>
	</environments>
	<!-- 将sql映射文件注册到全局配置文件中 -->
	<mappers>
		<mapper resource="pers/goodwin/mybatis/mapper/UserMapper.xml" />
	</mappers>
</configuration>

5.配合mapper文件

UserMapper.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">
  <select id="selectBlog" resultType="Blog">
    select * from Blog where id = #{id}
  </select>
</mapper>  
 -->
<mapper namespace="UserMapper">
  <select id="selectUserById" parameterType="Integer" resultType="pers.goodwin.mybatis.bean.User">
    select * from t_user where u_id = #{id}
  </select>
</mapper>

6.编写测试代码

package pers.goodwin.mybatis.test;
import java.io.IOException;
import java.io.InputStream;
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 org.junit.Test;
import pers.goodwin.mybatis.bean.User;

public class UserTest {
	@Test
	//入门程序 通过用户ID查询用户 
	public void test_selectUser() throws IOException {
		// 读取配置文件
		InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
		//需要sqlSessionFactoryBuilder
		SqlSessionFactoryBuilder ssb = new SqlSessionFactoryBuilder();
		//创建sqlSessionFactory
		SqlSessionFactory sqlSessionFactory = ssb.build(inputStream);
		// 根据配置文件构建会话工厂对象
		//SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);	
		// 通过SqlSessionFactory创建SqlSession
		SqlSession sqlSession = sqlSessionFactory.openSession();
		// 执行映射文件中定义的SQL并返回映射结果
		//参数1:要操作的SQL语句,参数2:SQL的参数
		User user = sqlSession.selectOne("UserMapper.selectUserById", 1);
		System.out.println(user);
	}
}

运行结果:

log4j:WARN No appenders could be found for logger (org.apache.ibatis.logging.LogFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
User [u_id=1, u_username=老王, u_password=12345, u_gender=0, u_cid=1]

可以正常查到正确结果,但是很丑。

7.log4j.properties

写一个log4j.properties :日志文件,便于查看MyBatis操作数据库的过程。

#Global configuration
log4j.rootLogger=DEBUG,stdout
#Console configuration
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.layout.ConversionPattern=%5p [%t] - %m%n

重新运行:

Logging initialized using ‘class org.apache.ibatis.logging.slf4j.Slf4jImpl’ adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 543846639.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@206a70ef]
= => Preparing: select * from t_user where u_id = ?
= => Parameters: 1(Integer)
<== Total: 1
User [u_id=1, u_username=老王, u_password=12345, u_gender=0, u_cid=1]

从运行结果可以看到,数据库执行了select * from t_user where u_id = ? 语句。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值