Mybatis学习一 CRUD的实现

前言:关于 mybatis 的博文,我没有很详细的去介绍每个类、每个注解或每个配置标签的详细作用。更多情况下是直接通过代码的方式“不求甚解”的来学习如何使用 mybatis,如果想更深入了解 mybatis 的一些类、注解或标签的作用,可以下载文章最后的附件。它是官方文档的中文版,里面很详细介绍了 mybatis 的内容。

 

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

MyBatis 可以使用简单的XML或注解用于配置和原始映射,将接口和 Java 的 POJO 映射成数据库中的记录。

在使用 Mybatis 之前我们还需要做一些准备工作。

首先导入 Mybatis 的 jar 包,同时还需要导入 Mysql 驱动包

在 Mysql 数据库中新建库和表

create database test;
use test;
CREATE TABLE user(id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20), age INT);
INSERT INTO user(NAME, age) VALUES('Tom', 20);
INSERT INTO user(NAME, age) VALUES('Jack', 25);

准备工作完成后,我们就真正来看如何通过 mybatis 实现 CRUD

 文件结构如下图

 

新建一个叫 mybatis-test 的 java 工程,src 下新建一个名为 mybatis-conf.xml 的文件作为 Mybatis 的配置文件

<?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="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/test"/>
                <property name="username" value="root"/>
                <property name="password" value="000"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

注:

1. <environments> 的 default 属性有两个值,一个是指代开发模式:development;还有一个指代工作模式:work。 <environments> 中的 id 属性要与该属性一致。

2. <transactionManager> 中 type 属性标识了 Mybatis 中的两种事务管理器类型

a. JDBC:这个配置直接简单使用了JDBC的提交和回滚设置。它依赖于从数据源得到的连接来管理事务范围。

b. MANAGED:这个配置几乎没做什么。他从来不提交或回滚一个连接。而它会让容器来管理事务的整个生命周期(比如 Spring 或 J2EE 应用服务器的上下文)。默认情况下它会关闭连接。

3. dataSource 元素使用基本的JDBC数据源接口来配置JDBC连接对象的资源。有三种内建的数据源类型

a. UNPOOLED:这个数据源的实现是每次被请求时简单打开和关闭连接。

b. POOLED:这是JDBC连接对象的数据源连接池的实现,用来避免创建新的连接实例时必要的初始连接和认证时间。

c. JNDI:这个数据源的实现是为了使用如 Spring 或应用服务器这类的容器,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的引用。

 

接下来,新建一个与数据库对应的实体类

package com.bupt.mybatis.beans;

public class User
{
    private int id;
    private String name;
    private int age;
   
  //生成 getter、setter方法,带参和不带参的构造器,重写toString
}

 

Mybatis 真正的方便之处在于映射语句中。如果你将它们和对等功能的JDBC代码来比较的话,你会发现映射文件节省了大量的代码量。Mybatis的构建就是聚焦于SQL的,使其原理普通的方式。

所以这里我们需要定义操作 user 表的 SQL 映射文件 userMapper.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">

<!-- namespace 属性值通常写为:映射文件所在包名+映射文件名去掉.xml后缀 --!>
<mapper namespace="com.bupt.mybatis.beanMappers.userMapper">
  <!-- parameterType指定查询时传递参数的类型,resultType为查询结果类型,需要写全类名 --!>
  <select id="getUser" parameterType="int" resultType="com.bupt.mybatis.beans.User"> select * from user where id=#{id} </select>
  <!-- 用#{}方式来作为传参占位符,括号内的元素需与定义在实体类中的属性一致 --!> <insert id="addUser" parameterType="com.bupt.mybatis.beans.User"> insert into user(id, name, age) values(#{id}, #{name}, #{age}) </insert>
   <!-- parameterType为测试时传入的参数类型 --!> <delete id="deleteUser" parameterType="int"> delete from user where id=#{id} </delete> <update id="updateUser" parameterType="com.bupt.mybatis.beans.User"> update user set name=#{name}, age=#{age} where id=#{id} </update>
  <!-- 当查询多条语句时,返回值为List<T>类型的,但其每条记录还是User类型 --!> <select id="getAll" resultType="com.bupt.mybatis.beans.User"> select * from user </select> </mapper>

 

编写好SQL映射文件后,我们还需要将此配置信息注册到 mybatis-conf.xml 文件中,注册时使用 <mappers> 和 <mapper> 标签,位置为 <environments>外,<configuration> 内

注意文件位置和编写格式

<mappers>
    <mapper resource="com/bupt/mybatis/beanMappers/userMapper.xml"/>
</mappers>

 

配置好 SQL 映射文件后,我们就可以编写测试类了

注:每个线程都应该有自己的 SqlSession 实例,SqlSession 的实例不能共享使用,它是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能把 SqlSession 实例放在一类的静态字段甚至是实例字段中。也绝对不能将 SqlSession 实例的引用放在任何类型的管理范围内,比如 Servlet 架构中的 HttpSession。

package com.bupt.mybatis.test;

import java.io.InputStream;
import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import com.bupt.mybatis.beans.User;

public class TestCRUD
{

   //指明需要加载的mybatis配置文件,需要写绝对路径
      String resource = "mybatis-conf.xml";
        
   //类加载加载 mybatis 配置文件
   InputStream is = TestCRUD.class.getClassLoader().getResourceAsStream(resource);
     SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);

   //使用 mybatis 提供的工具类 Resources 加载 mybatis 的配置文件
   //Reader reader = Resources.getResourceAsReader(resource);
   //SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
    
    @Test
    public void testSelect()
    {
        //如果要往数据库中提交事务,需要传递参数true。如果没有设置参数true,则执行完SQL语句后,数据库中不会有对应的记录
        SqlSession session = sessionFactory.openSession(true);
        
        //statement格式为:SQL映射文件中的namespace+要执行的SQL语句在映射文件中的id值
        String statement = "com.bupt.mybatis.beanMappers.userMapper.getUser";
        
        //session操作要放在try-catch模块中,下面的方法没写是偷懒
        try
        {
            User user = session.selectOne(statement, 2);
        
            //除了在openSession()方法中传递true参数之外,还可以使用commit()方法手动提交事务
            //session.commit();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            //关闭资源
            session.close();
        }
        
        System.out.println(user);
    }
    
    public void testAdd()
    {
        SqlSession session = sessionFactory.openSession(true);
        String statement = "com.bupt.mybatis.beanMappers.userMapper.addUser";
        
        int i = session.insert(statement, new User(3, "Jerry", 40));
        session.close();
        System.out.println(i);
    }
    
    public void testDelete()
    {
        SqlSession session = sessionFactory.openSession(true);
        String statement = "com.bupt.mybatis.beanMappers.userMapper.deleteUser";
        
        int i = session.delete(statement, 3);
        session.close();
        System.out.println(i);
    }
    
    public void testUpdate()
    {
        SqlSession session = sessionFactory.openSession(true);
        String statement = "com.bupt.mybatis.beanMappers.userMapper.updateUser";
        
        int i = session.update(statement, new User(2, "Kim", 22));
        session.close();
        System.out.println(i);
    }
    
    public void testSelectAll()
    {
        SqlSession session = sessionFactory.openSession(true);
        String statement = "com.bupt.mybatis.beanMappers.userMapper.getAll";
        
        List<User> users = session.selectList(statement);
        session.close();
        System.out.println(users);
    }
}

 

除了通过编写SQL映射文件的方式来实现 Mybatis 的CRUD之外,还可以通过注解的方式来实现

首先我们需要定义 SQL 映射的接口

package com.bupt.mybatis.annoMappers;

import java.util.List;

import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import com.bupt.mybatis.beans.User;

public interface UserMapper
{
    @Select("select * from user where id=#{id}")
    public User getUserById(int id);
    
    @Select("select * from user")
    public List<User> getAllUser();
    
    @Insert("insert into user(id, name, age) values (#{id}, #{name}, #{age})")
    public int insertUser(User user);
    
    @Delete("delete from user where id=#{id}")
    public int deleteUserById(int id);
    
    @Update("update user set name=#{name}, age=#{age} where id=#{id}")
    public int updateUser(User user);
}

 

在 mybatis-conf.xml 中注册这个映射的接口,位置与编写的xml形式的映射文件一致,但需要注意两者注册信息书写格式的区别

    <mappers>
        <mapper class="com.bupt.mybatis.annoMappers.UserMapper"/>
    </mappers>

用这种方式实现时,我们就不用编写映射文件 userMapper.xml

 

编写测试类

注:映射器实例的最佳范围是方法范围。

package com.bupt.mybatis.test;

import java.io.InputStream;
import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import com.bupt.mybatis.annoMappers.UserMapper1;
import com.bupt.mybatis.beans.User;

public class TestCRUDByAnno
{
    InputStream is = TestCRUDByAnno.class.getClassLoader().getResourceAsStream("mybatis-conf.xml");
    SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);

    //偷懒写法,要把session操作放入try-catch模块
    public void testGetUserById()
    {
        SqlSession session=sessionFactory.openSession(true);
        UserMapper mapper=session.getMapper(UserMapper1.class);
        
        User user = mapper.getUserById1(1);
        session.close();
        System.out.println(user);
    }

    public void testGetAll()
    {
        SqlSession session=sessionFactory.openSession(true);
        UserMapper mapper=session.getMapper(UserMapper1.class);
        
        List<User> users = mapper.getAllUser();
        session.close();
        System.out.println(users);
    }

    public void testInsertUser()
    {
        SqlSession session=sessionFactory.openSession(true);
        UserMapper mapper=session.getMapper(UserMapper1.class);
        
        int i = mapper.insertUser1(new User(3, "Jack", 30));
        session.close();
        System.out.println(i);
    }

    @Test
    public void testDeleteUser()
    {
        SqlSession session=sessionFactory.openSession(true);
        UserMapper mapper=session.getMapper(UserMapper1.class);
        
        int i = mapper.deleteUserById1(3);
        session.close();
        System.out.println(i);
    }

    public void testUpdate()
    {
        SqlSession session=sessionFactory.openSession(true);
        UserMapper mapper=session.getMapper(UserMapper1.class);
        
        int i = mapper.updateUser(new User(2, "Lily", 25));
        session.close();
        System.out.println(i);
    }
}

 

 

在实际中,用的更多的情况其实是 配置映射文件 + 接口的方式来实现 CRUD

这时我们在接口类中只定义方法,而不在其上面添加注解,需注意的是接口中的方法名需与在映射配置文件中定义的 id 属性一致

package com.bupt.mybatis.annoMappers;

import java.util.List;

import com.bupt.mybatis.beans.User;

public interface UserMapper1
{
    public User getUserById(int id);
    
    public List<User> getAllUser();
    
    public int insertUser(User user);
    
    public int deleteUserById(int id);
    
    public int updateUser(User user);
}

 

在编写映射配置文件时需注意,此时的 namespace 属性值需要与接口类的全类名一致,如此才能将映射文件与接口类关联起来

<?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.bupt.mybatis.annoMappers.UserMapper1">

    <select id="getUserById" parameterType="int" resultType="User">
        select * from user where id=#{id}
    </select>

    <select id="getAllUser" resultType="User">
        select * from user
    </select> 

    <insert id="insertUser" parameterType="User">
        insert into user(id, name, age) values(#{id}, #{name}, #{age})
    </insert>

    <delete id="deleteUserById" parameterType="int">
        delete from user where id=#{id}
    </delete>

    <update id="updateUser" parameterType="User">
        update user set name=#{name}, age=#{age} where id=#{id}
    </update>

</mapper>

测试类与之前注解修饰接口时使用的测试类一致。

 

 

在上面的程序中,还有几个可以优化的地方

1. 连接数据库的配置可以单独放置到一个properties文件中

##src下新建db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql:///test
username=root
password=000

相应的 mybatis-conf.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>
    <properties resource="db.properties"/>
<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> </configuration>

 

 2. 在编写SQL映射文件指定 parameterType 或 resultType 时,会大量使用到实体类的全名,非常麻烦。

我们可以在 mybatis-conf.xml 中声明一个类别名来代替使用,声明时使用 <typeAliases> 标签,位置<environments>外,<configuration>内

    <typeAliases>
        <!-- 当在SQL映射文件中出现com.bupt.mybatis.beans.User时,就可以用_User来代替了 -->
       <typeAlias type="com.bupt.mybatis.beans.User" alias="_User"/>
    </typeAliases>

 

但当存在大量的实体类时,我们就需要编写大量的声明标签,同样很麻烦。

在实际编写代码时,我们通常把实体类放置到同一个包下,这时我们就可以使用 <typeAliases> 中另外一个 <package name=""/> 标签,来简化存在多个实体类情况下的声明

当我们在 <package> 标签中的 name 属性填写了某个实体类包名时,编写SQL映射文件时不在需要写实体类的全类名,也不需要手动指定别名,直接默认使用类名代替即可,如此例中。

    <typeAliases>
        <package name="com.bupt.mybatis.beans"/>
    </typeAliases>

当我们作了如上说明,当在SQL映射文件中出现 com.bupt.mybatis.beans.User (全类名)时,就可以用User(类名)来代替了。

 

Mybatis 中文官方文档

https://files.cnblogs.com/files/2015110615L/MyBatis-3-User-Guide-Simplified-Chinese.pdf

posted on 2016-04-02 10:10  Traveling_Light_CC  阅读(185)  评论(0编辑  收藏  举报

导航