MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。 MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及结果集的检索。 MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的 POJOs(Plan Old Java Objects,普通的 Java对象)映射成数据库中的记录
1) 数据库连接的创建、释放频繁造成系统资源浪费从而影响了性能,如果使用数据库连接池就可以解决这个问题。当然JDBC同样能够使用数据源。
2) SQL语句在写代码中不容易维护,事件需求中SQL变化的可能性很大,SQL变动需要改变JAVA代码。
3) 向SQL语句传递参数麻烦,因为SQL语句的where条件不一定,可能多,也可能少,占位符需要和参数一一对应。
4) 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
配置文件对于MyBatis来说非常重要,MyBatis总共有两类配置文件:
一类用于指定数据源、事务属性以及其他一些参数配置信息(通常是一个独立的文件,可以称之为全局配置文件);
另一类则用于 指定数据库表和程序之间的映射信息(可能不止一个文件,我们称之为映射文件)
我们先来编写一个简单的入门程序,在编写的过程中介绍MyBatis处理问题的思路和方法。
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`)
);
XML 配置文件中包含了对 MyBatis 系统的核心设置,包含获取数据库连接实例的数据源(DataSource)和决定事务作用域和控制方式的事务管理器(TransactionManager)。要注意 XML 头部的声明,它用来验证 XML 文档正确性。environment 元素体中包含了事务管理和连接池的配置。mappers 元素则是包含一组映射器(mapper),这些映射器的 XML 映射文件包含了 SQL 代码和映射定义信息。下面是全局配置文件最关键的部分:
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<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>
<mapper resource="com/xx/mapper/ProductMapper.xml"/>
mappers>
configuration>
<mapper namespace="com.xx.mapper.ProductMapper">
mapper>
# 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
……
<configuration>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
settings>
……
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;
}
}
至此,我们的基础工作就做好了,接下来就可以实现功能了,来看此时的项目结构:
<mapper namespace="com.xx.mapper.ProductMapper">
<insert id="insertProductInfo" parameterType="com.xx.entity.Product">
insert into t_product values(
#{id},
#{name},
#{code},
#{price},
#{count},
#{description},
#{status},
#{create_time}
);
insert>
mapper>
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();
}
}
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.
id | name | code | price | count | description | status | create_time |
---|---|---|---|---|---|---|---|
1 | 华为手机 | 10001 | 4499 | 10 | 国产手机品牌 | 1 | 2019-04-17 22:20:32 |
我们的第一个功能:新增商品信息就完成了,接下来我们根据这个流程,依次来实现其余功能:
……
<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>
@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();
}
……
<mapper namespace="com.xx.mapper.ProductMapper">
……
<select id="selectInfoById" parameterType="int" resultType="com.xx.entity.Product">
select * from t_product where id = #{这里写任意变量名}
select>
mapper>
@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.
……
<mapper namespace="com.xx.mapper.ProductMapper">
……
<delete id="deleteProductById" parameterType="int">
delete from t_product where id = #{id}
delete>
mapper>
@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.
现在我们往表中多加几条信息:
id | name | code | price | count | description | status | create_time |
---|---|---|---|---|---|---|---|
2 | 华为手机 | 10001 | 4499 | 10 | 国产手机品牌 | 1 | 2019-04-18 13:56:19 |
3 | 小米手机 | 10002 | 3499 | 20 | 国产手机品牌 | 1 | 2019-04-18 14:04:56 |
4 | 一加手机 | 10003 | 3999 | 15 | 国产手机品牌 | 1 | 2019-04-18 14:06:02 |
现在我们来利用MyBatis实现查询商品列表:
……
<mapper namespace="com.xx.mapper.ProductMapper">
……
<select id="selectAllProduct" resultType="com.xx.entity.Product">
select * from t_product
select>
mapper>
@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
……
<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>
@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