首页 > 技术文章 > MyBatis入门

wanghj-15 2019-07-13 22:51 原文

1、MyBatis的介绍

  1. MyBatis 是一个支持普通SQL查询,存储过程和高级映射的优秀持久层(Dao)框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。

  2. MyBatis 消除了几乎所有的JDBC代码和手工设置参数以及结果集的检索。

  3. MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

  4. 一个MyBatis的应用程序都以一个SqlSessionFactory 对象(单例)的实例为核心;

    SqlSession对象完全包含以数据库为背景的所有执行SQL操作的方法。

  5. MyBatis是针对数据库交互的一个辅助框架,也是对jdbc做了的简单封装,以xml配置代替Java代码来管理数据库的交互细节!!

  注意:

    JPA 可以自动建表。

    MyBatis不能自动创建表,如果要建表,必须自己先准备好建表的sql语句。

 

MyBatis三大核心对象
    1. SqlSessionFactoryBuilder
          目的是创建SqlSessionFactory  ,  用完就扔  , 写在方法内部 , 作为局部变量 , 建造者模式。
    2. SqlSessionFactory
          重量级对象 , 作用域整个应用  , 单例模式使用  , 有二级缓存。
    3. SqlSession
        轻量级的  ,  请求作用域,一个请求对应一个SqlSession对象 , 线程不安全的 , 有一级缓存。
    4. (扩展)Executor 数据库的操作都是调用的Executor接口的方法
                update:增、删、改所用方法。
                query:查询所用方法。

 

MyBatis执行流程: 

  ①:我们需要核心文件(提供联系数据库的环境)

  ②:需要映射文件(提供ORM与运行的SQL语句)

  ③:拿到SqlSession对象,用于执行SQL

 

2、MyBatis的入门使用

  注意:

    使用Mybatis的方式用两种,一种是xml配置的方式,一种是接口+注解的方式。

    这里主要是介绍xml配置方式。

 

  1.导入相应的jar包

    核心包:mybatis-3.2.1.jar

    数据库驱动包:mysql-connector-java-5.1.26-bin.jar

    依赖包:
           
asm-3.3.1.jar
            cglib-2.2.2.jar
            commons-logging-1.1.1.jar
            javassist-3.17.1-GA.jar
            log4j-1.2.17.jar
            slf4j-api-1.7.2.jar
            slf4j-log4j12-1.7.2.jar

  2.准备相应的数据

    数据库-->新建数据库-->新建表-->插入测试数据

   3.准备domain实体类、dao和测试类

    注意:类的名称和类型都和我们的product表相对应匹配

  案例:

domain实体类

public class Product {
    private    Long id;
    //商品名称
    private String productName;
    //品牌
    private String brand;
    //供应商
    private String supplier;
    //零售价
    private Double salePrice;
    //进价
    private Double costPrice;
    //折扣比例
    private Double cutoff;
    //商品分类编号
    private Long dir_id;

  -----之后是get、set方法(略)
}

 

dao层接口

public interface IProductDao {
    /**
     * 添加一个商品
     */
    void save(Product p);
    /**
     * 更新一个商品
     */
    void update(Product product);
    /**
     * 删除一个商品
     */
    void delete(Long id);
    /**
     * 查询一个商品
     */
    Product findOne(Long id);
    /**
     * 查询所有商品
     */
    List<Product> findAll();

}

 

dao层接口实现类 

  注:添加、修改、删除的时候一定要记住提交事务(配置事务、表结构支持事务)。

 

    JDBC的事务是自动提交的,而JPA、Hibernate、MyBatis事务都是需要手动提交的。

 

package cn.wang.dao.daoImpl;

import cn.wang.Utils.MyBatisUtils;
import cn.wang.dao.IProductDao;
import cn.wang.domain.Product;
import org.apache.ibatis.session.SqlSession;

import java.util.ArrayList;
import java.util.List;

public class ProductDaoImpl implements IProductDao {

    //抽取sql命名空间名字的值
    private final String NAMESPACE = "cn.wang.domain.ProductMapper.";
    //添加方法
    @Override
    public void save(Product p) {
        SqlSession sqlSession =null;

        try {
            //获取SqlSession对象(MyBatisUtils是为了方便专门抽取出来的工具类)
            sqlSession = MyBatisUtils.getSession();
            //第一个参数:sql命名空间名字的值+对应sql语句映射的id,第二个参数:传入的值
            sqlSession.insert(NAMESPACE+"insert",p);
            //提交事务
            sqlSession.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession,释放资源(很重要,不然项目上线后会造成内存溢出)
            MyBatisUtils.colseSession(sqlSession);
        }
    }

    //修改方法
    @Override
    public void update(Product product) {
        SqlSession sqlSession = null;
        try {
            //获取SqlSession对象(MyBatisUtils是为了方便专门抽取出来的工具类)
            sqlSession = MyBatisUtils.getSession();
            //第一个参数:sql命名空间名字的值+对应sql语句映射的id,第二个参数:传入的值
            sqlSession.update(NAMESPACE+"update", product);
            //提交事务
            sqlSession.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession,释放资源(很重要,不然项目上线后会造成内存溢出)
            MyBatisUtils.colseSession(sqlSession);
        }
    }

    //删除方法
    @Override
    public void delete(Long id) {
        SqlSession sqlSession=null;

        try {
            //获取SqlSession对象(MyBatisUtils是为了方便专门抽取出来的工具类)
            sqlSession = MyBatisUtils.getSession();
            //第一个参数是获取查询语句:sql命名空间名字的值+对应sql语句映射的id
            sqlSession.delete(NAMESPACE+"delete", id);
            //提交事务
            sqlSession.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession,释放资源(很重要,不然项目上线后会造成内存溢出)
            MyBatisUtils.colseSession(sqlSession);
        }
    }

    //查询一条数据
    @Override
    public Product findOne(Long id) {
        SqlSession sqlSession = null;
        Product product= null;
        try {
            //获取SqlSession对象(MyBatisUtils是为了方便专门抽取出来的工具类)
            sqlSession = MyBatisUtils.getSession();
            //第一个参数是获取查询语句:sql命名空间名字的值+对应sql语句映射的id
            product = sqlSession.selectOne(NAMESPACE+"findOne", id);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession,释放资源(很重要,不然项目上线后会造成内存溢出)
            MyBatisUtils.colseSession(sqlSession);
        }
        return product;
    }

    //查询所有数据
    @Override
    public List<Product> findAll() {
        SqlSession sqlSession=null;
        List<Product> list=new ArrayList<>();

        try {
            //获取SqlSession对象(MyBatisUtils是为了方便专门抽取出来的工具类)
            sqlSession = MyBatisUtils.getSession();
            //第一个参数是获取查询语句:sql命名空间名字的值+对应sql语句映射的id
            list=sqlSession.selectList(NAMESPACE+"findAll");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession,释放资源(很重要,不然项目上线后会造成内存溢出)
            MyBatisUtils.colseSession(sqlSession);
        }
        return list;
    }
}

 

抽取出来的MyBatisUtils工具

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 java.io.Reader;

public class MyBatisUtils {
    //保证sqlSessionFactory是单例
    private static SqlSessionFactory sqlSessionFactory;

    // SqlSessionFactory类似于JPA的EntityManagerFactory,Hibernate的SessionFactory
    // SqlSession 类似于JPA的EntityManager,Hibernate的Session

    //该类被加载的时候就执行该静态代码块
    static {
        try {
            Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        } catch (Exception e) {//异常的类型要写大一些,才能够看到具体的报错
            e.printStackTrace();
        }
    }
    //提供一个外界调用的类
    public static SqlSession getSession(){
        //创建并返回SqlSession对象
        return sqlSessionFactory.openSession();
    }
    //关闭sqlSession,释放资源(很重要,不然项目上线后会造成内存溢出)
    public static void colseSession(SqlSession sqlSession){
        if(sqlSession !=null){
            sqlSession.close();
        }
    }
}

 

jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///数据库名称
jdbc.username=用户名
jdbc.password=密码

 

 

 

 

  3.MyBatis核心配置文件(mybatis-config.xml

<?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:默认使用哪一个环境(必须对应一个环境的id)
     -->

    <!--引入外部的属性文件
        不写classpath的原因:resources默认到classpath中寻找资源
    -->
    <properties resource="jdbc.properties" />

    <!--
        配置自定义别名
        注意:别名不区分大小写。
           共两种配置方式:
            一:一个一个配置(typeAlias)
                    type 类型的完全限定名
                    alias 别名
            二:统一为某个包下的所有类起别名(package)
                    name : 包名   别名就是类名(不区分大小写)
    -->
    <typeAliases>
        <!--方法一-->
        <!--<typeAlias type="cn.wang.domain" alias="Product"/>-->

        <!--方法二-->
        <package name="cn.wang.domain"/>
    </typeAliases>

    <environments default="development">
        <!--
            environment:一个环境  id:为这个环境取唯一一个id名称
        -->
        <environment id="development">
            <!--
                transactionManager:事务管理(共有两个值) type:JDBC(支持事务)/MANAGED(什么都不做)
            -->
            <transactionManager type="JDBC" />
            <!-- 数据源, 连接池  type(POOLED):MyBatis自带的连接池
                     type="UNPOOLED" 不使用连接池
                    type="POOLED" 使用连接池
                    type="JNDI" 容器中使用
             -->
            <dataSource type="POOLED">
                <!-- 连接数据库的参数 -->
                <property name="driver" value="${jdbc.driver}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
    </environments>
    <!-- 注册映射文件,这个mappers代表的是相应的ORM映射文件 -->
    <mappers>
        <mapper resource="cn/wang/domain/ProductMapper.xml" />
    </mappers>

</configuration>

 

  4.配置映射文件(命名方式:domain实体类名称+Mapper.xml

   注意:

    ① 我们的映射文件在这里是和它对应的domain实体类在同一个层级
        ② 这个映射文件的名称一般叫做 XxxMapper.xml (Xxx代表的是实体类名称)
        ③ namespace的名称为了确定唯一性,请大家根据我的要求取名
            如我们有一个类:
            cn.itsource.domain.Product / cn.itsource.domain.Student
            那这里取名应该是:
            cn.itsource.domain.ProductMapper /cn.itsource.domain.StudentMapper
        ④ 类型都通通使用全限定名

<?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的主要功能就是写sql
    mapper:根
    namespace:命令空间 (用来确定唯一性) 以前这个是可以不加的,现在必需加
     namespace的值,规则的:映射文件XxxMapper.xml所在的包+domain类名+Mapper
 -->
<mapper namespace="cn.wang.domain.ProductMapper">
    <!--
        select : 这里面写查询语句
        id:sql语句的标识,在同一个namespace下不能重复

        parameterType : 传入的参数类型(原本应该用的是全限定名,这里用的是别名)  long:大Long  _long:小long (具体的对应请参见文档)
        resultType : 返回的结果类型(每一条数据返回的对象类型) 自己的对象一定是全限定类名(这里写的是别名)
     -->
    <select id="findOne" parameterType="long" resultType="Product">
        select * from product where id=#{id}
    </select>
    <!--别名不区分大小写-->
    <select id="findAll" resultType="product">
        select * from product
    </select>

    <insert id="insert" parameterType="product" keyProperty="id" useGeneratedKeys="true">
        insert into product(productName,dir_id,salePrice,supplier,brand,cutoff,costPrice) VALUES (
          #{productName},
          #{dir_id},
          #{salePrice},
          #{supplier},
          #{brand},
          #{cutoff},
          #{costPrice}
        )
    </insert>

    <update id="update" parameterType="long">
        UPDATE product set productName=#{productName} where id=#{id}
    </update>

    <delete id="delete" parameterType="long">
        delete FROM product where id=#{id}
    </delete>
</mapper>

 

  5.最后进行测试

public class MybatisTest {
    private IProductDao productDao=new ProductDaoImpl();

    @Test
    public void testFindOne(){
        Product product = productDao.findOne(1L);
        System.out.println(product);
    }

    @Test
    public void testFindAll(){
        List<Product> list = productDao.findAll();
        for (Product product : list) {
            System.out.println(product);
        }
    }

    @Test
    public void testInsert(){
        Product product = new Product();
        product.setProductName("大金刚");
        product.setDir_id(3L);
        product.setSalePrice(100.00);
        product.setSupplier("哈哈哈");
        product.setBrand("哇咔咔");
        product.setCutoff(0.66);
        product.setCostPrice(23.00);

        productDao.save(product);
        //获取新添加数据的主键,前提insert标签已经配置了那三个属性
        System.out.println(product.getId());
    }

    @Test
    public void testUpdate(){
       Product product = productDao.findOne(1L);
       product.setProductName("大罗金仙");
       productDao.update(product);
    }
    @Test
    public void testDelete(){

       productDao.delete(1L);
    }

}

 

 

 

 

 

 

 

 

推荐阅读