MyBatis(一)——MyBatis简介、MyBatis入门程序

MyBatis简介

什么是MyBatis?

MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。 MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及结果集的检索。 MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的 POJOs(Plan Old Java Objects,普通的 Java对象)映射成数据库中的记录

JDBC编程存在的问题?MyBatis如何解决?

1) 数据库连接的创建、释放频繁造成系统资源浪费从而影响了性能,如果使用数据库连接池就可以解决这个问题。当然JDBC同样能够使用数据源。

  • 解决:在SQLMapConfig.xml中配置数据连接池,使用数据库连接池管理数据库连接。

2) SQL语句在写代码中不容易维护,事件需求中SQL变化的可能性很大,SQL变动需要改变JAVA代码。

  • 解决:将SQL语句配置在mapper.xml文件中与java代码分离。

3) 向SQL语句传递参数麻烦,因为SQL语句的where条件不一定,可能多,也可能少,占位符需要和参数一一对应。

  • 解决:Mybatis自动将java对象映射到sql语句。

4) 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。

  • 解决:Mbatis自动将SQL执行结果映射到java对象。

MyBatis的工作原理

配置文件对于MyBatis来说非常重要,MyBatis总共有两类配置文件:

  • 一类用于指定数据源、事务属性以及其他一些参数配置信息(通常是一个独立的文件,可以称之为全局配置文件);

  • 另一类则用于 指定数据库表和程序之间的映射信息(可能不止一个文件,我们称之为映射文件

Mybatis大概的执行过程:
在这里插入图片描述

MyBatis入门程序

我们先来编写一个简单的入门程序,在编写的过程中介绍MyBatis处理问题的思路和方法。

  • 需求:新增商品信息、修改商品信息、删除商品信息、查询商品列表、根据id查询单个商品信息。

准备工作

  • 新建商品表:
CREATE TABLE `t_product` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(255),
  `code` VARCHAR(255),
  `price` DOUBLE(10,0),
  `count` INT(11),
  `description` VARCHAR(255),
  `status` INT(255),
  `create_time` DATETIME,
  PRIMARY KEY (`id`)
);
  • 搭建MyBatis开发环境:
  1. 将 mybatis-x.x.x.jar 文件置于 classpath 中即可。
  2. 将数据库驱动jar包置于classpath中(这两个jar包通常配合使用)。
    效果图:
    在这里插入图片描述
  3. 添加全局配置文件mybatis-config.xml到项目src目录下。

XML 配置文件中包含了对 MyBatis 系统的核心设置,包含获取数据库连接实例的数据源(DataSource)和决定事务作用域和控制方式的事务管理器(TransactionManager)。要注意 XML 头部的声明,它用来验证 XML 文档正确性。environment 元素体中包含了事务管理和连接池的配置。mappers 元素则是包含一组映射器(mapper),这些映射器的 XML 映射文件包含了 SQL 代码和映射定义信息。下面是全局配置文件最关键的部分:

<!-- 头部声明 -->
<?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是mybatis配置文件的根标签,用来配置mybatis运行环境等信息 -->
<configuration>
  <!-- environments用来配置mybatis运行环境:数据源,事务管理…… -->
  <!-- 一个environment代表一种运行环境,默认是development -->
  <environments default="development">
    <environment id="development">
   <!-- transationManager的type表示的是mybatis的事务管理采用的是JDBC数据管理 -->
      <transactionManager type="JDBC"/>
      <!-- mybatis所应用的数据源,type表示的是数据源采用数据库连接池 -->
      <dataSource type="POOLED">
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/0417test"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
      </dataSource>
    </environment>
  </environments>
  
  <!-- mappers用来配置mybatis要加载的mapper.xml文件或者mapepr接口 -->
  <mappers>
		<!--在这里加载映射器-->
		<mapper resource="com/xx/mapper/ProductMapper.xml"/>
  </mappers>
</configuration>
  1. 创建映射器com\xx\mapper\ProductMapper.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是mapper.xml文件的根标签,mapper标签内,编写sql语句
	namespace:命名空间,区分每个mapper.xml
    取值格式:mapper文件所在包的包名.mapper文件名(不带后缀)
 -->  
<mapper namespace="com.xx.mapper.ProductMapper">
  	<!-- 在这里用标签编写sql语句 -->
</mapper>
  1. 添加log4j.properties文件到src目录下,更改全局配置文件:
    日志是应用软件中不可缺少的部分,Apache的开源项目Log4j是一个功能强大的日志组件,提供方便的日志记录。MyBatis的jar包中整合了Log4j功能,我们只需要添加配置文件然后更改全局配置文件就可以使用了:
  • 在src目录下创建log4j.properties并添加:
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
  • 更改mybatis-config.xml:
……
<configuration>
	<settings>
		<!-- 配置mybatis日志采用的是log4j -->
		<setting name="logImpl" value="STDOUT_LOGGING" />
	</settings>
	……
	
  1. 创建实体类com\xx\entity\Product.class,与数据库中表t_product相对应:
package com.xx.entity;

import java.util.Date;

public class Product {
	// CREATE TABLE `t_product` (
	// `id` INT(11) NOT NULL AUTO_INCREMENT,
	// `name` VARCHAR(255),
	// `code` VARCHAR(255),
	// `price` DOUBLE(10,0),
	// `count` INT(11),
	// `description` VARCHAR(255),
	// `status` INT(255),
	// `create_time` DATETIME,
	// PRIMARY KEY (`id`)
	// );
	private Integer id;
	private String name;
	private String code;
	private Double price;
	private Integer count;
	private String description;
	private Integer status;
	private Date create_time;

	public Product() {
		super();
		// TODO Auto-generated constructor stub
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public Double getPrice() {
		return price;
	}

	public void setPrice(Double price) {
		this.price = price;
	}

	public Integer getCount() {
		return count;
	}

	public void setCount(Integer count) {
		this.count = count;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public Integer getStatus() {
		return status;
	}

	public void setStatus(Integer status) {
		this.status = status;
	}

	public Date getCreate_time() {
		return create_time;
	}

	public void setCreate_time(Date create_time) {
		this.create_time = create_time;
	}

}

至此,我们的基础工作就做好了,接下来就可以实现功能了,来看此时的项目结构:
在这里插入图片描述

功能实现

第一个功能:insert-新增商品信息

  1. 更改ProductMapper.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="com.xx.mapper.ProductMapper">
  <!-- 新增商品信息 id:表示用来区分sql语句 -->
  <!-- parameterType表示输入的参数类型,可以是java的基础数据类型和引用数据类型 -->
  <insert id="insertProductInfo" parameterType="com.xx.entity.Product">
		<!-- 在insert标签中写sql语句,#{}表示占位符,里面写传入参数的属性值(即product.xxx) -->
  		insert into t_product values(
  			#{id},
  			#{name},
  			#{code},
  			#{price},
  			#{count},
  			#{description},
  			#{status},
  			#{create_time}
  		);
  </insert>
</mapper>
  1. 编写测试类com\xx\test\MyTest.class:
package com.xx.test;

import java.io.IOException;
import java.util.Date;

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 com.xx.entity.Product;

public class MyTest {
	// 这里我们使用单元测试,单元测试有几个规范:
	// public 无参 无返回值 方法名以test开头
	// 使用单元测试需要将JUnit4添加到classpath中
	@Test
	public void testInsertProductInfo() throws IOException {
		// 每一个 MyBatis 的应 用程序 都以一 个 SqlSessionFactory 对象的 实例为 核心。
		// SqlSessionFactory 对 象 的 实 例 可以 通 过 SqlSessionFactoryBuilder 对 象 来 获得。
		// SqlSessionFactoryBuilder 对象可以从 XML 配置文件
		// 或从 Configuration 类的实例中构建 SqlSessionFactory 对象

		// 1.获取到SqlSessionFactory对象
		SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder()
				.build(Resources.getResourceAsReader("mybatis-config.xml"));
		// 2.获取SqlSession对象
		SqlSession session = sessionFactory.openSession();
		// 3.创建product对象
		Product product = new Product();
		product.setName("华为手机");
		product.setCode("10001");
		product.setPrice(4499.00);
		product.setCount(10);
		product.setDescription("国产手机品牌");
		product.setStatus(1);
		product.setCreate_time(new Date());
		// 4.插入数据insert:
		// 第一个参数是要执行的sql语句(我们已经写在ProductMapper.xml中),它的取值是 namespece+id
		// 第二个参数就是执行sql语句传递的参数,类型是parameterType所指定的参数类型
		session.insert("com.xx.mapper.ProductMapper.insertProductInfo", product);
		// 5.手动提交事务
		session.commit();
		// 6.释放资源
		session.close();
	}
}

  1. 执行结果:
  • 控制台
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' 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 1386767190.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@52a86356]
==>  Preparing: insert into t_product values( ?, ?, ?, ?, ?, ?, ?, ? ); 
==> Parameters: null, 华为手机(String), 10001(String), 4499.0(Double), 10(Integer), 国产手机品牌(String), 1(Integer), 2019-04-17 22:20:32.562(Timestamp)
<==    Updates: 1
Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@52a86356]
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@52a86356]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@52a86356]
Returned connection 1386767190 to pool.

  • 数据库
idnamecodepricecountdescriptionstatuscreate_time
1华为手机10001449910国产手机品牌12019-04-17 22:20:32

我们的第一个功能:新增商品信息就完成了,接下来我们根据这个流程,依次来实现其余功能:

update-根据id更改信息

  • ProductMapper.xml
……
<mapper namespace="com.xx.mapper.ProductMapper">
 	……
  <update id="alterPriceById" parameterType="com.xx.entity.Product">
  		update t_product set price = #{price} where id = #{id}
  </update>
</mapper>
  • MyTest.class
	@Test
	public void testAlterPriceById() throws IOException {
		SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder()
				.build(Resources.getResourceAsReader("mybatis-config.xml"));
		SqlSession session = sessionFactory.openSession();
		Product product = new Product();
		// 更改华为手机的价格
		product.setId(1);
		product.setPrice(5000.00);
		session.update("com.xx.mapper.ProductMapper.alterPriceById", product);
		session.commit();
		session.close();
	}

select-通过id来查询商品信息

  • ProductMapper.xml
……
<mapper namespace="com.xx.mapper.ProductMapper">
 	……
     <!-- 有必要说明一下parameterType的值为引用类型和基础数据类型的区别 :
  	      如果是基础数据类型、String那么#{}中可以使任何变量名,包括中文和value
          如果是引用数据类型(自定义的entity),那么#{}中必须是entity所包含的属性名-->
  <select id="selectInfoById" parameterType="int" resultType="com.xx.entity.Product">
  		select * from t_product where id = #{这里写任意变量名}
  </select>
</mapper>
  • MyTest.class
@Test
public void testSelectInfoById() throws IOException {
	SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder()
			.build(Resources.getResourceAsReader("mybatis-config.xml"));
	SqlSession session = sessionFactory.openSession();
	// 查询id为1的商品信息,返回类型是Product
	Product product = session.selectOne("com.xx.mapper.ProductMapper.selectInfoById", 1);
	// 这里返回Product重写toString方法以便输出
	// 如果我们有log4j,就没有必要输出,可以直接在控制台查看返回的信息
	System.out.println(product);
	session.commit();
	session.close();
}
  • 控制台
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' 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 540642172.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@20398b7c]
==>  Preparing: select * from t_product where id = ? 
==> Parameters: 1(Integer)
<==    Columns: id, name, code, price, count, description, status, create_time
<==        Row: 1, 华为手机, 10001, 5000, 10, 国产手机品牌, 1, 2019-04-17 22:20:32.0
<==      Total: 1

Product [id=1, name=华为手机, code=10001, price=5000.0, count=10, description=国产手机品牌, status=1, create_time=Wed Apr 17 22:20:32 CST 2019]

Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@20398b7c]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@20398b7c]
Returned connection 540642172 to pool.

根据id来删除信息

  • ProductMpper.mapper
……
<mapper namespace="com.xx.mapper.ProductMapper">
 	……
	<delete id="deleteProductById" parameterType="int">
  		delete from t_product where id = #{id}
    </delete>
  
</mapper>
  • MyTest.class
@Test
public void testDeleteProductById() throws IOException {
	SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder()
			.build(Resources.getResourceAsReader("mybatis-config.xml"));
	SqlSession session = sessionFactory.openSession();
	session.delete("com.xx.mapper.ProductMapper.deleteProductById", 1);
	session.commit();
	session.close();

}
  • 控制台
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' 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 2025864991.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@78c03f1f]
==>  Preparing: delete from t_product where id = ? 
==> Parameters: 1(Integer)
<==    Updates: 1
Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@78c03f1f]
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@78c03f1f]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@78c03f1f]
Returned connection 2025864991 to pool.

查询商品列表

现在我们往表中多加几条信息:

idnamecodepricecountdescriptionstatuscreate_time
2华为手机10001449910国产手机品牌12019-04-18 13:56:19
3小米手机10002349920国产手机品牌12019-04-18 14:04:56
4一加手机10003399915国产手机品牌12019-04-18 14:06:02

现在我们来利用MyBatis实现查询商品列表:

  • ProductMapper.mapper
……
<mapper namespace="com.xx.mapper.ProductMapper">
 	……
	<!-- 查询所有信息不需要传参,返回的肯定是一个列表,
	但是我们不需要指定resultType为list,只需要列表的数据类型就可以 -->
  <select id="selectAllProduct" resultType="com.xx.entity.Product">
  	select * from t_product 
  </select>
  
</mapper>
  • MyTest.class
@Test
public void testSelectAllProduct() throws IOException {
	SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder()
			.build(Resources.getResourceAsReader("mybatis-config.xml"));
	SqlSession session = sessionFactory.openSession();
	// selecrList
	// 返回类型是List<>类型
	List<Product> list = session.selectList("com.xx.mapper.ProductMapper.selectAllProduct");
	// 遍历输出一下
	Iterator<Product> iterator = list.iterator();
	while (iterator.hasNext()) {
		Product product = (Product) iterator.next();
		System.out.println(product);
	}

	session.commit();
	session.close();

}
  • 控制台
……
==>  Preparing: select * from t_product 
==> Parameters: 
<==    Columns: id, name, code, price, count, description, status, create_time
<==        Row: 2, 华为手机, 10001, 4499, 10, 国产手机品牌, 1, 2019-04-18 13:56:19.0
<==        Row: 3, 小米手机, 10002, 3499, 20, 国产手机品牌, 1, 2019-04-18 14:04:56.0
<==        Row: 4, 一加手机, 10003, 3999, 15, 国产手机品牌, 1, 2019-04-18 14:06:02.0
<==      Total: 3

Product [id=2, name=华为手机, code=10001, price=4499.0, count=10, description=国产手机品牌, status=1, create_time=Thu Apr 18 13:56:19 CST 2019]
Product [id=3, name=小米手机, code=10002, price=3499.0, count=20, description=国产手机品牌, status=1, create_time=Thu Apr 18 14:04:56 CST 2019]
Product [id=4, name=一加手机, code=10003, price=3999.0, count=15, description=国产手机品牌, status=1, create_time=Thu Apr 18 14:06:02 CST 2019]

……

新增商品返回主键

这里有必要介绍一个selectKey标签:

selectKey在新增后返回主键值时使用,表示查询主键的值,绑定给某个列或者类的某个属性
keyProperty:新增后返回的主键值赋给类的哪个属性
order:取值为BEFORE或者AFTER,BEFORE表示在执行insert语句之前执行select,After表示在执行insert语句之后执行select
LAST_INSERT_ID()将查询到的结果绑定到keyProperty

  • ProductMapper
……
<mapper namespace="com.xx.mapper.ProductMapper">
 	……
	<insert id="insertProductReturnPK" parameterType="com.xx.entity.Product" >
  		<selectKey keyProperty="id" resultType="int" order="AFTER">
  			select LAST_INSERT_ID()
  		</selectKey>
  		
  		insert into t_product values(
  			#{id},
  			#{name},
  			#{code},
  			#{price},
  			#{count},
  			#{description},
  			#{status},
  			#{create_time}
  		);
    </insert>
  
</mapper>
  • MyTest
@Test
public void testInsertProductReturnPK() throws IOException {
	SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder()
			.build(Resources.getResourceAsReader("mybatis-config.xml"));
	SqlSession session = sessionFactory.openSession();
	Product product = new Product();
	product.setName("vivo手机");
	product.setCode("10006");
	product.setPrice(4199.00);
	product.setCount(10);
	product.setDescription("国产手机品牌");
	product.setStatus(1);
	product.setCreate_time(new Date());
	// 插入数据后返回主键pk
	int pk = session.insert("com.xx.mapper.ProductMapper.insertProductReturnPK", product);
	session.commit();
	session.close();
	}
  • 控制台
……
==>  Preparing: insert into t_product values( ?, ?, ?, ?, ?, ?, ?, ? ); 
==> Parameters: null, vivo手机(String), 10006(String), 4199.0(Double), 10(Integer), 国产手机品牌(String), 1(Integer), 2019-04-18 14:51:03.886(Timestamp)
<==    Updates: 1
==>  Preparing: select LAST_INSERT_ID() 
==> Parameters: 
<==    Columns: LAST_INSERT_ID()
<==        Row: 5
<==      Total: 1
……

可见,新插入的这条数据的主键值是5。

以上,我们介绍了MyBatis的用途和特点,还编写了一个简单的小程序,接下来主要讲讲MyBatis的全局配置文件:
https://blog.csdn.net/qq_44238142/article/details/89380508

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值