MyBatis学习(二)SqlMapConfig.xml配置
示例工程:mybatis-demo2
本文档记录的是学习过程,主要描述了MyBatis中关于SqlMapConfig.xml的配置,版权所有
1、搭建MyBatis的开发环境
1.1、创建Maven项目
1)在IDEA中直接新建一个普通的maven项目
2)新建src/main/java目录、src/main/resources目录
3)新建src/test/java目录
4)新建对应的包路径com.iambest.study
- 对应的目录结构如下所示:
├── pom.xml
├── README.md
├── src
│ ├── main
│ │ ├── java
│ │ └── resources
│ └── test
│ ├── java
│ └── resources
└── target
1.2、引入jar包依赖
在pom.xml中引入我们需要的jar包,包括:
1)mysql的数据库驱动
2)mybatis的jar依赖包
3)dbcp的数据库连接策略
pom.xml
的依赖部分如下所示:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<!-- 引入mysql的数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.30</version>
</dependency>
<!-- 引入MyBatis的maven jar包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!-- 数据库连接池策略 -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>
</dependencies>
2、使用SqlMapConfig.xml配置MyBatis
2.1、配置SqlMapConfig.xml
文件
1)在MyBatis中,通过SqlMapConfig.xml配置文件,进行配置MyBatis的基本信息
2)通过SqlSessionFactoryBuilder构建SqlSessionFactory工厂对象
3)然后通过SqlSessionFactory获取SqlSession
4)我们的核心操作都依赖SqlSession来完成,三大核心对象如下:
SqlSessionFactoryBuilder
SqlSessionFactory
SqlSession
1)首先,我们来配置我们的SqlMapConfig-sqlSession.xml文件
2)在resources/config目录下新建该文件,内容如下
SqlMapConfig-sqlSession.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN"
"http://ibatis.apache.org/dtd/ibatis-3-config.dtd">
<configuration>
<environments default="environment">
<environment id="environment">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/david"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</dataSource>
</environment>
</environments>
</configuration>
2.2、单元测试验证
2.2.1、编写单元测试代码
1)我们通过编写单元测试的方式,验证我们的配置是否生效
2)如下是我们编写的单元测试用例代码
TestSqlSession
package com.iambest.study;
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 java.io.IOException;
import java.io.Reader;
/**
* 测试SQLSession类
*/
public class TestSqlSession {
@Test
public void testSqlSession() throws IOException {
String config = "config/SqlMapConfig-sqlSession.xml";
Reader reader = Resources.getResourceAsReader(config);
// 创建Builder对象
SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
// 创建Factory对象
SqlSessionFactory factory = sfb.build(reader);
// 通过factory对象生成session对象
SqlSession session = factory.openSession();
System.out.println(session);
session.close();
}
}
2.2.2、执行单元测试
运行我们的单元测试用例,如下图所示,表示我们的配置没有问题:
3、使用SqlMapConfig.xml结合mapper.xml实现数据库CRUD
本示例中使用到数据库表的建表语句如下:
-- mysql的建表脚本
create table t_student_info(
id varchar(20) not null comment '主键',
name varchar(50) default ' ' comment '姓名',
age decimal(3) default 20 comment '年龄',
sex char(1) default 'M' comment '性别 M-男,W-女',
phone varchar(20) comment '手机号',
email varchar(30) comment '电子邮箱',
rsv1 varchar(100) comment '备注字段',
primary key (id)
) engine=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 COMMENT '学生信息表';
-- 订单信息表
create table tb_order_info(
order_id varchar(10) not null comment '订单id',
payment decimal(18,2) default 0.00 comment '支付金额',
goods_name varchar(256) default '' comment '商品名称',
payment_type char(1) default '1' comment '支付类型 : 1-在线支付,2-货到付款',
post_fee decimal(18,2) default 0.00 comment '邮费',
status char(1) default '1' comment '订单状态:1-未付款,2-已付款,3-未发货,4-已发货,5-交易成功,6-交易关闭',
create_time date comment '订单创建时间',
constraint pk_order_id primary key(order_id)
) engine=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 comment '订单信息表';
3.1、insert操作
3.1.1、配置文件及实体类
1)需要修改我们的SqlMapConfig文件
SqlMapConfig-insert.xml
,增加mappers节点,并引入我们的sqlMapper文件2)新建sqlMapper文件
StudentInfoMapper
,并添加我们需要的方法,这里是:addStudentInfo
SqlMapConfig
- 首先我们配置一下我们的SqlMapConfig文件
SqlMapConfig-insert.xml
- 在
SqlMapConfig-insert.xml
文件中添加mappers节点,并引入sqlMapper文件,如下:
<?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="environment">
<environment id="environment">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/david"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</dataSource>
</environment>
</environments>
<!-- 手工引入我们的mapper.xml文件 -->
<mappers>
<mapper resource="config/mapper/StudentInfoMapper.xml"></mapper>
</mappers>
</configuration>
StudentInfoMapper
- 看一下我们的数据库mapper文件,
StudentInfoMapper
- mapper文件的路径在:resources/config/mapper路径下
- 在其中增加
addStudentInfo
方法,内容如下:
<?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.iambest.study.dao.StudentInfoMapper">
<!-- 登记数据库表 -->
<insert id="addStudentInfo" parameterType="com.iambest.study.entity.StudentInfoDo">
insert into t_student_info (id,name,age,sex,phone,email,rsv1)
values
(#{id},#{name},#{age},#{sex},#{phone},#{email},#{rsv1})
</insert>
</mapper>
StudentInfoDo
StudentInfoDo
为数据表的映射文件- 这里我们将其与数据库的字段一一对应起来,内容如下:
package com.iambest.study.entity;
import java.util.Objects;
/**
* StudentInfoDo数据实体</br>
*
* <b>映射的是t_student_info数据库表的字段</b>
*
*/
public class StudentInfoDo {
private String id;
private String name;
private Integer age;
private String sex;
private String phone;
private String email;
private String rsv1;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getRsv1() {
return rsv1;
}
public void setRsv1(String rsv1) {
this.rsv1 = rsv1;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
StudentInfoDo that = (StudentInfoDo) o;
return Objects.equals(id, that.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
@Override
public String toString() {
return "StudentInfoDo{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", phone='" + phone + '\'' +
", email='" + email + '\'' +
", rsv1='" + rsv1 + '\'' +
'}';
}
}
3.1.2、编写单元测试代码
1)配置完成之后,我们在test目录下编写单元测试代码,测试insert
testInsert
方法
@Test
public void testInsert() throws IOException {
String config = "config/SqlMapConfig-insert.xml";
Reader reader = Resources.getResourceAsReader(config);
// 创建Builder对象
SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
// 创建Factory对象
SqlSessionFactory factory = sfb.build(reader);
// 通过factory对象生成session对象
SqlSession session = factory.openSession();
// 这里我们手工创studentInfo建一个新的对象
StudentInfoDo studentInfo = new StudentInfoDo();
studentInfo.setId("10002");
studentInfo.setName("李四");
studentInfo.setSex("W");
studentInfo.setAge(18);
studentInfo.setPhone("18100002222");
studentInfo.setEmail("lisi@163.com");
studentInfo.setRsv1("这里是李四的备注");
// 打印一下李四的信息
System.out.println(studentInfo);
// 使用sqlSession对象执行插入操作
session.insert("addStudentInfo",studentInfo);
// 提交事务
session.commit();
// 关闭
session.close();
System.out.println("执行插入成功!");
}
3.1.3、测试并验证结果
1)执行单元测试用例,看一下控制台的输出以及数据库的数据是否插入成功
- 执行单元测试用例,控制台的输出:
- 查询数据库,新增数据成功:
3.2、update操作
3.2.1、配置文件
1)在sqlMapper文件
StudentInfoMapper.xml
文件中,添加update方法updateById
StudentInfoMapper
<!-- 根据ID更新数据库 -->
<update id="updateById" parameterType="com.iambest.study.entity.StudentInfoDo">
update t_student_info set NAME=#{name},AGE=#{age},SEX=#{sex},PHONE=#{phone},
EMAIL=#{email},RSV1=#{rsv1} where ID=#{id}
</update>
3.2.2、编写单元测试代码
1)编写单元测试代码
testUpdate
,将已经存在的信息进行更新,
testUpdate
@Test
public void testUpdate() throws IOException{
String config = "config/SqlMapConfig-insert.xml";
Reader reader = Resources.getResourceAsReader(config);
// 创建Builder对象
SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
// 创建Factory对象
SqlSessionFactory factory = sfb.build(reader);
// 通过factory对象生成session对象
SqlSession session = factory.openSession();
// 这里我们手工创studentInfo建一个新的对象
StudentInfoDo studentInfo = new StudentInfoDo();
studentInfo.setId("10002");
studentInfo.setName("李四");
studentInfo.setSex("W");
studentInfo.setAge(18);
// 把手机号修改掉
studentInfo.setPhone("15988887777");
studentInfo.setEmail("lisi@163.com");
// 把备注信息修改掉
studentInfo.setRsv1("李四是张三的妹妹");
// 打印一下李四的信息
System.out.println(studentInfo);
// 使用sqlSession对象执行更新操作
session.insert("updateById",studentInfo);
// 提交事务
session.commit();
// 关闭
session.close();
System.out.println("执行更新成功!");
}
3.2.3、测试并验证结果
1)执行单元测试用例,查看控制台的数据,并通过终端工具查看更新的结果
- 执行单元测试,查看单元测试用例结果,如下:
- 查看数据库的更新结果,李四的手机号及备注已经被更新,表示成功了,如下:
3.3、select操作
3.3.1、配置文件
1)查询操作,我们这里通过ID进行查询,在
StudentInfoMapper
文件中添加selectById
方法2)返回的结果集,我们通过对象
StudentInfoDo
的方式进行包装3)同时,我们添加查询所有结果的方法
findAll
,其返回结果是一个对象的列表集合4)我们预置了一条数据,id为10003
StudentInfoMapper
中添加selectById
方法,如下:
<!-- 根据ID查询 -->
<select id="selectById" resultType="com.iambest.study.entity.StudentInfoDo">
select id,name,age,sex,phone,email,rsv1 from t_student_info where ID=#{id}
</select>
findAll
方法
<select id="findAll" resultType="com.iambest.study.entity.StudentInfoDo">
select id,name,age,sex,phone,email,rsv1 from t_student_info
</select>
3.3.2、编写单元测试代码
1)在测试类中添加
testSelectById
方法,测试根据ID的查询结果2)添加
testFindAll
方法,测试查询所有记录的查询方法
testSelectById
@Test
public void testSelectById() throws IOException{
String config = "config/SqlMapConfig-insert.xml";
Reader reader = Resources.getResourceAsReader(config);
// 创建Builder对象
SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
// 创建Factory对象
SqlSessionFactory factory = sfb.build(reader);
// 通过factory对象生成session对象
SqlSession session = factory.openSession();
StudentInfoDo studentInfoDo = session.selectOne("selectById","10003");
System.out.println(studentInfoDo);
session.close();
}
testFindAll
@Test
public void testFindAll() throws IOException {
String config = "config/SqlMapConfig-insert.xml";
Reader reader = Resources.getResourceAsReader(config);
// 创建Builder对象
SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
// 创建Factory对象
SqlSessionFactory factory = sfb.build(reader);
// 通过factory对象生成session对象
SqlSession session = factory.openSession();
List<StudentInfoDo> lists = session.selectList("findAll");
for (StudentInfoDo node : lists) {
System.out.println(node);
}
session.close();
}
3.3.3、测试并验证结果
1)分别通过运行单元测试,测试查询的结果
testSelectById
- 查看控制台的输出
testFindAll
- 查看控制台的输出
3.4、delete操作
3.4.1、配置文件
1)在SQLMapper文件中,添加根据id删除数据的方法
deleteById
StudentInfoMapper
<!-- 根据ID进行删除 -->
<delete id="deleteById" parameterType="java.lang.String">
delete from t_student_info where ID=#{id}
</delete>
3.4.2、编写单元测试代码
1)编写单元测试代码
testDelete
,删除我们刚刚预置的数据
testDelete
@Test
public void testDelete() throws IOException {
String config = "config/SqlMapConfig-insert.xml";
Reader reader = Resources.getResourceAsReader(config);
// 创建Builder对象
SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
// 创建Factory对象
SqlSessionFactory factory = sfb.build(reader);
// 通过factory对象生成session对象
SqlSession session = factory.openSession();
int resultTot = session.delete("deleteById","10003");
System.out.println("成功删除的总条数为:" + resultTot);
// 提交事务
session.commit();
session.close();
}
3.4.3、测试并验证结果
1)执行我们的单元测试用例,查看控制台的输出,
2)通过终端工具查询数据库,验证数据是否真的被删除
- 执行测试用例,查看控制台的输出
- 查询数据库,验证数据是否被真的删除了;这里可以看到数据已经被删除
3.5、说明
- 我们的示例代码中,mybatis默认获取到的sqlsession是不能自动提交事务的
- 那么DML语句执行完成之后,需要手工执行commit,才能提交事务,使操作失效
- 如果想自动提交事务,需要在opensession(true)时,设置autoCommit为true即可
4、使用RowBounds实现分页查询(强烈不推荐)
4.1、预置数据
1)我们预置了一个订单表tb_order_info,里面通过程序生成了50万条数据,利用此表来实现分页查询
4.1.1、预置数据的相关代码
实体类OrderInfo
1)OrderInfo 实体类与tb_order_info字段进行映射,属性采用驼峰命名法
2)完整代码如下:
package com.iambest.study.entity;
import java.math.BigDecimal;
import java.util.Date;
/**
*
*/
public class OrderInfo {
private String orderId;
private BigDecimal payment;
private String goodsName;
private String paymentType;
private BigDecimal postFee;
private String status;
private Date createTime;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public BigDecimal getPayment() {
return payment;
}
public void setPayment(BigDecimal payment) {
this.payment = payment;
}
public String getGoodsName() {
return goodsName;
}
public void setGoodsName(String goodsName) {
this.goodsName = goodsName;
}
public String getPaymentType() {
return paymentType;
}
public void setPaymentType(String paymentType) {
this.paymentType = paymentType;
}
public BigDecimal getPostFee() {
return postFee;
}
public void setPostFee(BigDecimal postFee) {
this.postFee = postFee;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
@Override
public String toString() {
return "OrderInfo [orderId=" + orderId + ", payment=" + payment
+ ", goodsName=" + goodsName + ", paymentType=" + paymentType
+ ", postFee=" + postFee + ", status=" + status
+ ", createTime=" + createTime + "]";
}
}
数据库连接的工具类ConnectionSource
1)ConnectionSource类通过读取配置文件、封装了获取数据库连接的方法
2)同时使用了连接池的策略,完整代码如下:
package com.iambest.study.utils;
import org.apache.commons.dbcp.BasicDataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class ConnectionSource {
private static BasicDataSource dataSource = null;
private ConnectionSource() {
}
public static void init() {
Properties prop = new Properties();
try {
prop.load(ConnectionSource.class.getClassLoader()
.getResourceAsStream("config/db_mysql.properties"));
} catch (IOException e) {
e.printStackTrace();
}
String driver = prop.getProperty("jdbc.driver");
String url = prop.getProperty("jdbc.url");
String username = prop.getProperty("jdbc.username");
String password = prop.getProperty("jdbc.password");
String initialSize = prop.getProperty("dataSource.initialSize");
String minIdle = prop.getProperty("dataSource.minIdle");
String maxIdle = prop.getProperty("dataSource.maxIdle");
String maxWait = prop.getProperty("dataSource.maxWait");
String maxActive = prop.getProperty("dataSource.maxActive");
dataSource = new BasicDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
if (initialSize != null && initialSize.trim().length() != 0) {
dataSource.setInitialSize(Integer.parseInt(initialSize));
}
if (minIdle != null && minIdle.trim().length() != 0) {
dataSource.setMinIdle(Integer.parseInt(minIdle));
}
if (maxIdle != null && maxIdle.trim().length() != 0) {
dataSource.setMaxIdle(Integer.parseInt(maxIdle));
}
if (maxWait != null && maxWait.trim().length() != 0) {
dataSource.setMaxWait(Integer.parseInt(maxWait));
}
if (maxActive != null && maxActive.trim().length() != 0) {
dataSource.setMaxActive(Integer.parseInt(maxActive));
}
}
/**
*
* @return
* @throws SQLException
*/
public static synchronized Connection getConnection() throws SQLException {
if (dataSource == null) {
System.out.println("dataSource对象为空,调用创建对象的方法");
init();
}
Connection conn = null;
if (dataSource != null) {
conn = dataSource.getConnection();
}
return conn;
}
}
数据库配置文件db_mysql.properties
1)db_mysql.properties 配置了数据库连接的相关信息
#JDBC Connection INFO
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/david
jdbc.username=root
jdbc.password=123456
#JDBC Pool INFO
dataSource.initialSize=10
dataSource.maxIdle=20
dataSource.minIdle=5
dataSource.maxActive=50
dataSource.maxWait=1000
预置50万条数据TestInitDataBaseData
1)我们通过批量提交的方式,初始化50万条数据到mysql的数据库
2)代码如下:
package com.iambest.study;
import com.iambest.study.entity.OrderInfo;
import com.iambest.study.utils.ConnectionSource;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;
import java.util.Random;
/**
*
* 初始化数据库表中的数据
*
* @author zhang_wei
*
*/
public class TestInitDataBaseData {
private static final Random rand = new Random();
private static final String paymentTypes[] = new String[] { "1", "2" };
private static final BigDecimal payments[] = new BigDecimal[] {
new BigDecimal("5299.00"), new BigDecimal("5899.00"),
new BigDecimal("6099.00"), new BigDecimal("4999.00") };
private static final String status[] = new String[] { "1", "2", "3", "4",
"5", "6" };
private static final String goodsKind[] = new String[] { "iPhone X ",
"iPhone XS ", "华为Mate 30 ", "小米8 ", "锤子手机 ", "华为Mate30 Pro " };
private static final String goodsSize[] = new String[] { "64G ", "128G ",
"256G ", "512 G" };
private static final String goodsColor[] = new String[] { "白色 ", "银灰色 ",
"红色 ", "黑色 " };
private static final BigDecimal postFees[] = new BigDecimal[] {
new BigDecimal("5.00"), new BigDecimal("10.00"),
new BigDecimal("8.00"), new BigDecimal("0.00") };
public static void main(String[] args) throws SQLException {
TestInitDataBaseData tst = new TestInitDataBaseData();
System.out.println("开始初始化数据...");
long start = System.currentTimeMillis();
tst.initMysqlData();
long end = System.currentTimeMillis();
System.out.println("初始化数据完成...");
System.out.println("总耗时:" + (end - start) + " ms");
}
/**
*
* 初始化数据
*
* @throws SQLException
*/
public void initData() throws SQLException {
Connection conn = ConnectionSource.getConnection();
String sql = "insert into david.tb_order_info(order_id,payment,goods_name,payment_type,post_fee,status,create_time) "
+ "values(seq_order_id.nextval,?,?,?,?,?,?)";
PreparedStatement prep = conn.prepareStatement(sql);
for (int i = 0; i < 1000; i++) {
long start = System.currentTimeMillis();
for (int j = 0; j < 1000; j++) {
OrderInfo order = genOrderInfo();
prep.setBigDecimal(1, order.getPayment());
prep.setString(2, order.getGoodsName());
prep.setString(3, order.getPaymentType());
prep.setBigDecimal(4, order.getPostFee());
prep.setString(5, order.getStatus());
prep.setDate(6, new java.sql.Date(order.getCreateTime()
.getTime()));
prep.addBatch();
}
prep.executeBatch();
prep.clearBatch();
long end = System.currentTimeMillis();
System.out.println("执行成功:" + i +" 总耗时:" + (end - start) + " ms");
}
prep.close();
conn.close();
}
/**
*
* MySQL的数据初始化
*
* @throws SQLException
*/
public void initMysqlData() throws SQLException{
Connection conn = ConnectionSource.getConnection();
int index = 102000000;
String sql = "insert into tb_order_info(payment,goods_name,payment_type,post_fee,status,create_time,order_id) "
+ "values(?,?,?,?,?,?,?)";
PreparedStatement prep = conn.prepareStatement(sql);
for (int i = 0; i < 500; i++) {
long start = System.currentTimeMillis();
for (int j = 0; j < 1000; j++) {
OrderInfo order = genOrderInfo();
prep.setBigDecimal(1, order.getPayment());
prep.setString(2, order.getGoodsName());
prep.setString(3, order.getPaymentType());
prep.setBigDecimal(4, order.getPostFee());
prep.setString(5, order.getStatus());
prep.setDate(6, new java.sql.Date(order.getCreateTime()
.getTime()));
prep.setString(7, String.valueOf(index));
index ++;
prep.addBatch();
}
long aa = System.currentTimeMillis();
prep.executeBatch();
prep.clearBatch();
long bb = System.currentTimeMillis();
System.out.println("生成数据的时间:" + (aa-start));
System.out.println("插入的执行时间:" + (bb-aa));
long end = System.currentTimeMillis();
System.out.println("执行成功:" + i +" 总耗时:" + (end - start) + " ms\r\n");
}
prep.close();
conn.close();
}
/**
*
* 随机生成一个OrderInfo实体对象
*
* @return 随机生成的OrderInfo实体对象
*/
public static OrderInfo genOrderInfo() {
OrderInfo orderInfo = new OrderInfo();
orderInfo.setPayment(payments[getIndex(payments.length)]);
orderInfo.setGoodsName(goodsKind[getIndex(goodsKind.length)]
+ goodsColor[getIndex(goodsColor.length)]
+ goodsSize[getIndex(goodsSize.length)]);
orderInfo.setPaymentType(paymentTypes[getIndex(paymentTypes.length)]);
orderInfo.setPostFee(postFees[getIndex(postFees.length)]);
orderInfo.setCreateTime(new Date());
orderInfo.setStatus(status[getIndex(status.length)]);
return orderInfo;
}
/**
*
* 根据指定长度,随机生成下标
*
* @param length
* 指定的长度
* @return 下标
*/
public static int getIndex(int length) {
return rand.nextInt(length);
}
}
4.2、RowBounds实现分页查询
原理:
1)MyBatis中实现分页的原理是将所有的数据都查出来,放到内存中,而后通过上送的参数进行截取
缺点:
1)由于需要将所有符合条件的数据全部查询出来,并放到内存中,因此当查询的结果集过大时,容易产生内存溢出
2)结果集的数据量过大,也会导致查询速度便面,增加数据库的压力
3)因此我们强烈不推荐使用该方式来实现分页查询,本文只是为了阐述原理
解决方案:(后续我专门写一篇文章来实现)
1)需要重写MyBatis的相关组件,来实现自定义的分页查询实现策略
2)mysql和oracle的分页实现策略是不一样的,我在另一篇文章中专门阐述了相关的实现方式,请移步链接
4.2.1、调整SqlMapConfig.xml文件
1)在原有的SqlMapConfig.xml文件
SqlMapConfig-insert.xml
中引入我们新建的OrderInfoMapper.xml文件
<!-- 手工引入我们的mapper.xml文件 -->
<mappers>
<mapper resource="config/mapper/StudentInfoMapper.xml"></mapper>
<mapper resource="config/mapper/OrderInfoMapper.xml"/>
</mappers>
4.2.2、新建OrderInfoMapper.xml文件
1)在resources/config/mapper目录下新建文件
OrderInfoMapper.xml
OrderInfoMapper.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.iambest.study.dao.OrderInfoMapper">
<!-- 这里为了和entity中的字段映射上,每个字段使用别名进行包装 -->
<select id="findAllOrderInfos" resultType="com.iambest.study.entity.OrderInfo">
select order_id AS ORDERID,
payment AS PAYMENT,
goods_name AS GOODS_NAME,
payment_type AS PAYMENTTYPE,
post_fee AS POSTFEE,
status AS STATUS,
create_time AS CREATETIME
from tb_order_info
</select>
</mapper>
4.2.3、编写单元测试用例并测试
1)我们这里查询的数据为,从第100001个下标开始,查询10条数据
2)代码如下所示:
题外话:
1)一般来说,我们封装的分页查询需要上送的参数是当前页和每页显示的条数,通过自己的计算,赋值给SQL语句需要的起始下标和查询的条数
- TestPage
package com.iambest.study;
import java.io.IOException;
import com.iambest.study.entity.OrderInfo;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.Reader;
import java.util.List;
/**
* 分页测试用例
*/
public class TestPage {
@Test
public void testPage() throws IOException{
String config = "config/SqlMapConfig-insert.xml";
Reader reader = Resources.getResourceAsReader(config);
// 创建Builder对象
SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
// 创建Factory对象
SqlSessionFactory factory = sfb.build(reader);
// 通过factory对象生成session对象
SqlSession session = factory.openSession();
//起点坐标
int offset = 100001;
// 查询几个
int limit = 10;
RowBounds rowBounds = new RowBounds(offset, limit);
List<OrderInfo> list = session.selectList("findAllOrderInfos",null,rowBounds);
for (OrderInfo order: list) {
System.out.println(order);
}
}
}
- 执行单元测试用例,查看控制台的输出如下,表示成功:
5、使用Map作为返回的结果集
5.1、配置文件
1)我们在上文中所有的返回结果集都是一个实体对象
2)不过MyBatis也支持将返回的结果集封装成Map对象
3)对于常用的数据类型及集合框架中的几种类型,MyBatis封装了一些简写方式,我们配置的使用不需要再配置全称路径
- 配置我们的sqlMapper文件
OrderInfoMapper.xml
,新增一个方法selectByOrderId
- 内容如下:
<select id="selectByOrderId" resultType="java.util.HashMap" parameterType="string">
select * from tb_order_info where order_id=#{order_id}
</select>
5.2、单元测试用例及测试
1) 我们编写单元测试,测试返回结果为Map
- testMap
@Test
public void testMap() throws IOException {
String config = "config/SqlMapConfig-insert.xml";
Reader reader = Resources.getResourceAsReader(config);
// 创建Builder对象
SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
// 创建Factory对象
SqlSessionFactory factory = sfb.build(reader);
// 通过factory对象生成session对象
SqlSession session = factory.openSession();
Map<String,Object> resultMap = session.selectOne("selectByOrderId","102000000");
System.out.println(resultMap);
System.out.println(resultMap.get("GOODS_NAME"));// 娶不到值,key为小写
session.close();
}
- 运行单元测试,看控制台的输出,输出的结果为map,如下:
6、使用Mapper接口实现数据库操作
问题探讨:
1)在上述的过程中,我们发现每次都是通过sqlSession对象来操作数据库实现CRUD的操作,非常的繁琐
2)在MyBatis中还有另外一种方式,我们可以通过Mapper接口来实现数据库的操作
思路:
1)编写一个Mapper接口,该Mapper接口和SqlMapper同名,并在SqlMapper中的命名空间指定
2)在Mapper接口中编写方法,并且方法的名称和SqlMapper中的每个id的命名保持一致
3)通过SqlSession提供的getMapper方法,来获取一个Mapper接口实例
4)我们通过该接口实例及对应的方法来实现数据库的操作
6.1、编写Mapper接口
1)编写接口
StudentInfoMapper
文件2)在
StudentInfoMapper
中一一编写对应sqlMapper.xml中的方法3)sqlMapper.xml文件中指定命名空间为:
com.iambest.study.dao.StudentInfoMapper
StudentInfoMapper
package com.iambest.study.dao;
import com.iambest.study.entity.StudentInfoDo;
import java.util.List;
/**
* 数据库Dao层
*/
public interface StudentInfoMapper {
/**
* 登记学生信息
* @param studentInfoDo
*/
public void addStudentInfo(StudentInfoDo studentInfoDo);
/**
* 更新学生信息
* @param studentInfoDo
*/
public void updateById(StudentInfoDo studentInfoDo);
/**
* 根据ID删除
* @param id
*/
public void deleteById(String id);
/**
* 根据ID进行查询
* @param id
* @return 查询的数据实体
*/
public StudentInfoDo selectById(String id);
/**
* 查询所有的记录
* @return
*/
public List<StudentInfoDo> findAll();
}
6.2、编写单元测试用例并测试
1)这里我们以
findAll
为示例,查询所有的记录信息,其他的大同小异,都是一样的处理逻辑2)编写单元测试用例
TestMapper
TestMapper
package com.iambest.study.mapper;
import com.iambest.study.dao.StudentInfoMapper;
import com.iambest.study.entity.StudentInfoDo;
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 java.io.IOException;
import java.io.Reader;
import java.util.List;
public class TestMapper {
@Test
public void testMapper() throws IOException {
String config = "config/SqlMapConfig-insert.xml";
Reader reader = Resources.getResourceAsReader(config);
// 创建Builder对象
SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
// 创建Factory对象
SqlSessionFactory factory = sfb.build(reader);
// 通过factory对象生成session对象
SqlSession session = factory.openSession();
// 获取到Mapper接口对象
StudentInfoMapper studentInfoMapper = session.getMapper(StudentInfoMapper.class);
// 通过mapper接口对象的方法执行查询
List<StudentInfoDo> lists = studentInfoMapper.findAll();
for (StudentInfoDo entry : lists) {
System.out.println(entry);
}
session.close();
}
}
- 运行单元测试,查看控制台的输出,如下图表示成功: