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。

posted @ 2021-03-13 20:58  deng-hui  阅读(461)  评论(0编辑  收藏  举报