zoukankan      html  css  js  c++  java
  • 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 中文官方文档

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

  • 相关阅读:
    linux学习笔记
    HDMI之CEC DDC学习笔记(可能有误)
    MAP按照value排序
    Map遍历四种方法
    Java native方法
    [PAT] 1143 Lowest Common Ancestor (30 分)Java
    [PAT] 1148 Werewolf
    [PAT] 1096 Consecutive Factors (20 分)Java
    [PAT] 1092 To Buy or Not to Buy (20 分)Java
    [PAT] 1088 Rational Arithmetic (20 分)Java
  • 原文地址:https://www.cnblogs.com/2015110615L/p/5818895.html
Copyright © 2011-2022 走看看