MyBatis(一)如何使用MyBatis及实现CRUD
我们之前在Java中都是使用JDBC来操作数据的,先来回顾一下JDBC的操作:
package jdbc;
import java.sql.*;
public class JDBC01 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接对象
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/practice","root","root");
// conn.setAutoCommit(false);
//3.获取执行者对象
String sql = "select * from emp where ename = ?";
ps = conn.prepareStatement(sql);
ps.setString(1,"SMITH");
//4.执行sql
rs = ps.executeQuery();
//5.处理结果集
while (rs.next()){
rs.getInt("empno");
//......
}
// conn.commit();
} catch (ClassNotFoundException e) {
// try {
// conn.rollback();
// } catch (SQLException ex) {
// ex.printStackTrace();
// }
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
//6.关闭资源
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(ps != null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
可以发现,其中有很多的代码需要重复的去编写,如连接和释放,以及处理结果集;而且sql语句是书写在Java代码中的,如果后续需要优化sql语句的话,就需要重新编译,测试,发布等等。
所以就有了MyBatis这个持久层框架来代替JDBC
MyBatis文档(中文版):https://mybatis.org/mybatis-3/zh/index.html
(里面有详细的用法,可以好好的看一下,本文中大多数的内容也与该文档无异,本文更简洁一些)
文档里面也有关于mybatis的简介:
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
1.如何使用MyBatis
首先,需要导入mysql和mybatis的jar包:
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
然后书写mybatis-config.xml文件:
在官方文档中也可以直接粘贴修改,主要是数据库涉及的driver,url,username,password,放置在resource下
(在此处引入了外部属性文件,待会会提到)
(最后涉及到了mapper文件的引入)
<?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="jdbc.properties"/>
<typeAliases>
<package name="pojos"/>
</typeAliases>
<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>
<!-- 引入Mapper.xml文件-->
<mappers>
<mapper resource="mapper/ProductsMapper.xml"/>
</mappers>
</configuration>
涉及到的jdbc.properties:
放置在resource下,记得修改为自己的值。
即,在mybatis-config.xml中引入该文件,在使用右边的值时使用 :${左边的属性名} 。
driver = com.mysql.cj.jdbc.Driver
url = jdbc:mysql:///mybatisdb?serverTimezone=Asia/Shanghai&characterEncoding=utf8
username = root
password = root
以及涉及到的Mapper.xml文件:
(xxxMapper.xml文件(命名最好是JavaBean的名字+Mapper.xml)用来编写sql语句的,放置在resource下,可以再新建一个目录)
<?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="mapper">
<!-- 书写sql语句-->
</mapper>
数据库对应的javabean对象。
如:products表:
DROP TABLE IF EXISTS `products`;
CREATE TABLE `products` (
`pid` INT(11) NOT NULL AUTO_INCREMENT,
`pname` VARCHAR(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`price` DOUBLE NULL DEFAULT NULL,
`pdate` DATE NULL DEFAULT NULL,
`cid` VARCHAR(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`pid`) USING BTREE
) ENGINE = INNODB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;
INSERT INTO `products` VALUES (1, '泰国大榴莲', 98, NULL, 's001');
INSERT INTO `products` VALUES (2, '新疆大枣', 38, NULL, 's002');
INSERT INTO `products` VALUES (3, '新疆切糕', 68, NULL, 's001');
INSERT INTO `products` VALUES (4, '十三香', 10, NULL, 's002');
INSERT INTO `products` VALUES (5, '老干妈', 20, NULL, 's002');
对应的Products类:添上setter/getter和重写toString()
数据类型要一致,数据库的字段名与JavaBean的属性名也最好一致!一致的话可以避免一些不必要的麻烦,待会会演示不一致会怎么样
package pojos;
import java.util.Date;
public class Products {
private int pid;
private String pname;
private double price;
private Date pdate;
private String cid;
public int getPid() {
return pid;
}
public void setPid(int pid) {
this.pid = pid;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Date getPdate() {
return pdate;
}
public void setPdate(Date pdate) {
this.pdate = pdate;
}
public String getCid() {
return cid;
}
public void setCid(String cid) {
this.cid = cid;
}
@Override
public String toString() {
return "Products{" +
"pid=" + pid +
", pname='" + pname + '\'' +
", price=" + price +
", pdate=" + pdate +
", cid='" + cid + '\'' +
'}';
}
}
这时整个mybatis的框架就搭好了,剩下的就是在对应的Mapper.xml中书写sql语句,以及如何使用mybatis了。
此时有的内容有:
- mysql和mybatis对应的jar包
- mybatis-config.xml:配置driver、url、username、password,以及mapper.xml
- jdbc.properties:(driver、url、username、password的键值对)
- xxxMapper.xml:(namespace与书写sql语句)
- 数据库对应的JavaBean:数据类型一致,最好名字也一致
测试:select(by primaryKey)
在ProductsMapper.xml中书写sql语句。
<?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="mapper">
<!-- 书写sql语句-->
<!-- id为这条sql语句的唯一标识,parameterType为参数的数据类型,resultType为结果的数据类型-->
<!-- 参数使用#{参数}-->
<!-- 如果参数只有一个,并且数据类型为八种基本数据类型及其包装类,或者是String时,可以省略不写-->
<!-- select id="selectProductById" resultType="pojos.Products"-->
<select id="selectProductById" parameterType="int" resultType="pojos.Products">
select * from products where pid = #{pid};
</select>
</mapper>
使用单元测试:根据主键查询数据
单元测试的使用:导入junit的jar包,在项目/src/test/java里面编写代码,每一个方法都相当于一个main方法,可直接执行,只要在方法上方加上@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 org.junit.Test;
import pojos.Products;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
public class Test01 {
@Test
public void test01(){
//固定的方式
SqlSession session = null;
String resource = "mybatis-config.xml";
try {
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = builder.build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
// 可写作一行,也建议写作一行
// session = new SqlSessionFactoryBuilder().build(inputStream).openSession();
//session对象中包含很多执行sql语句的方法
Products product = session.selectOne("selectProductById", 1);
System.out.println(product);
} catch (IOException e) {
e.printStackTrace();
}finally {
if(session != null){
session.close();
}
}
}
}
运行test01:
Products{pid=1, pname='泰国大榴莲', price=98.0, pdate=null, cid='s001'}
测试:select(like)、insert、delete、update
在ProductsMapper.xml中书写sql语句。
<?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="mapper">
<!-- 书写sql语句-->
<!-- id为这条sql语句的唯一标识,parameterType为参数的数据类型,resultType为结果的数据类型-->
<!-- 参数使用#{参数}-->
<select id="selectProductById" parameterType="int" resultType="pojos.Products">
select * from products where pid = #{pid};
</select>
<!-- like模糊查询-->
<!-- 参数不是使用#,而是使用'%${}%'-->
<select id="selectProductsLikePname" parameterType="String" resultType="pojos.Products">
select * from products where pname like "%${pname}%";
</select>
<!-- 插入数据,参数为JavaBean,没有返回值-->
<!-- 此时参数为#{JavaBean的属性值}-->
<!-- keyProperty="pid" useGeneratedKeys="true"为获取自增的主键(必须是支持自增的数据库才可以)-->
<insert id="insertProducts" parameterType="pojos.Products" keyProperty="pid" useGeneratedKeys="true">
insert into products (pname,price,pdate,cid) values (#{pname},#{price},#{pdate},#{cid});
</insert>
<delete id="deleteProductById" parameterType="int">
delete from products where pid = #{pid};
</delete>
<!-- 修改要先获得原来的数据,再进行修改,参数为JavaBean-->
<update id="updateProductById" parameterType="pojos.Products">
update products set pname = #{pname} where pid = #{pid};
</update>
</mapper>
tset:
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 pojos.Products;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
public class Test01 {
@Test
public void test01(){
SqlSession session = null;
String resource = "mybatis-config.xml";
try {
InputStream inputStream = Resources.getResourceAsStream(resource);
// SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// SqlSessionFactory sqlSessionFactory = builder.build(inputStream);
// SqlSession session = sqlSessionFactory.openSession();
session = new SqlSessionFactoryBuilder().build(inputStream).openSession();
//根据主键查询单条数据
Products product = session.selectOne("selectProductById", 1);
System.out.println(product);
//模糊查询,结果为多条数据
List<Products> products = session.selectList("selectProductsLikePname", "新疆");
for (Products product1 : products) {
System.out.println(product1);
}
//以下为DML,别忘记commit()
//插入数据
Products p = new Products();
p.setPname("核桃");
p.setPdate(new Date());
p.setPrice(99);
p.setCid("s002");
int insert = session.insert("insertProducts", p);
session.commit();
System.out.println(insert);
System.out.println(p.getPid());
//删除数据
int delete = session.delete("deleteProductById", 6);
session.commit();
System.out.println(delete);
//修改数据,要先获取原来的数据再进行修改
Products product2 = session.selectOne("selectProductById", 7);
product.setPname("山核桃");
int update = session.update("updateProductById", product2);
session.commit();
System.out.println(update);
} catch (IOException e) {
if(session != null){
session.rollback();
}
e.printStackTrace();
}finally {
if(session != null){
session.close();
}
}
}
}
总结:
-
增删查改对应的标签为insert、delete、select、update;
-
parameterType的参数类型:
- 普通类型:八种基本数据类型和它们的包装类,以及String(可以省略)
- JavaBean类型
- Map
-
resultType的数据类型:
- JavaBean
- 集合(Map、List)
-
DML语句记得commit()
-
如果不想手动commit()的话,可以在获取session对象时添加一个参数
SqlSession session = sqlSessionFactory.openSession(true);
-
下一篇文章继续介绍mybatis。