Mybatis入门与Mapper动态代理

Mybatis简介

MyBatis 本是 apache 的一个开源项目 iBatis, 2010 年这个项目由 apache software foundation 迁移到了 google code,并且改名为 MyBatis 。2013 年 11 月迁移到 Github。

MyBatis 是一个优秀的持久层框架,它对 jdbc 的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建 connection、创建 statement、手动设置参数、结果集检索等 jdbc 繁杂的过程代码。

Mybatis 通过 xml 或注解的方式将要执行的各种 statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过j ava 对象和 statement 中的 sql 进行映射生成最终执行的 sql 语句,最后由 Mybatis 框架执行 sql 并将结果映射成 java 对象并返回。

Mybatis 架构

这里写图片描述
架构图详解:

1、mybatis配置
  SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
  mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加   载。
2、通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
3、由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
4、mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,
  一个是基本执行器、一个是缓存执行器。
5Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。
  mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
6Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,
  Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
7Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,
  Executor通过MappedStatement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。

Mybatis 入门

我们先来写一个入门程序,来了解一下 Mybatis 具体的使用流程,具体的细节会在后面一一讲解

第一步:创建数据库和数据表

CREATE DATABASE mybatis; 
CREATE TABLE `user` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `username` VARCHAR(32) NOT NULL COMMENT '用户名称',
  `birthday` DATE DEFAULT NULL COMMENT '生日',
  `sex` CHAR(1) DEFAULT NULL COMMENT '性别',
  `address` VARCHAR(256) DEFAULT NULL COMMENT '地址',
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;


INSERT INTO `user` VALUES ('1', '王五', NULL, '2', NULL);
INSERT INTO `user` VALUES ('10', '张三', '2014-07-10', '1', '广东深圳');
INSERT INTO `user` VALUES ('16', '张小明', NULL, '1', '广东广州');
INSERT INTO `user` VALUES ('22', '陈小明', NULL, '1', '广东广州');
INSERT INTO `user` VALUES ('24', '张三丰', NULL, '1', '广东广州');
INSERT INTO `user` VALUES ('25', '陈小明', NULL, '1', '广东广州');
INSERT INTO `user` VALUES ('26', '王五', NULL, NULL, NULL);

第二步:创建 java 项目,导入 DTD 约束文件和jar包,配置 Mybatis 核心配置文件sqlMapConfig.xml ,SqlMapConfig.xml 是配置文件内容为数据源、事务管理。(配置文件写在 src 根目录下即可,或者也可以在 src下创建一个文件夹 config,用于统一存放配置文件)
这里写图片描述

<?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>
    <typeAliases>
        <package name="com.pngyul.mybatis.pojo" />
    </typeAliases>
    <!-- 和spring整合后 environments配置将废除 -->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事务管理 -->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url"
                    value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
                <property name="username" value="root" />
                <property name="password" value="root" />
            </dataSource>
        </environment>
    </environments>
    <!--要引入映射文件 mapper.xml,该文件名字可以随意,但最好与你对应的数据库表名一致
        该User0.xml文件在第四步会写
      -->
    <mappers>
        <mapper resource="User0.xml" />
    </mappers>
</configuration>

第三步:创建和数据库表对应的 pojo 类

public class User implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private Integer id;
    private String username;// 用户姓名
    private String sex;// 性别
    private Date birthday;// 生日
    private String address;// 地址


    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    @Override
    public String toString() {
        return "User [id=" + id + ", username=" + username + ", sex=" + sex
                + ", birthday=" + birthday + ", address=" + address + "]";
    }
}

第四步:创建 sql 映射文件 Use0.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:命名空间,用于隔离sql,还有一个很重要的作用,后面会讲 --> 
<mapper namespace="test"> 
    <!--id为sql语句的id,parameterType为参数类型,resultType为结果类型,#{}为占位符-->
    <!--根据id查找用户,#{}里面可以随便写-->
    <select id="findUserById" parameterType="Integer" resultType="com.pngyul.mybatis.pojo.User">
        select * from user where id =#{id}
    </select>
</mapper>

第五步:测试程序

@Test
public void findUserById() throws IOException {
    // 加载核心配置文件
    String resource = "sqlMapConfig.xml";
    InputStream in = Resources.getResourceAsStream(resource);
    // 创建SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
    // 创建SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 执行Sql语句
    User user = sqlSession.selectOne("test.findUserById", 10);
    System.out.println(user);
    }

模糊查询

<!-- 模糊查询 -->
<select id="findUserByUsername" parameterType="String" resultType="com.pngyul.mybatis.pojo.User">
        select * from user where username like "%"#{haha}"%"
</select>
<!--sql 语句还有另一种写法-->
<!-- ${}里面只能是value -->
select * from user where username like '%${value}%'
//根据用户名称模糊查询用户列表
@Test
public void findUserByUsername() throws Exception {
    String resource = "sqlMapConfig.xml";
    InputStream in = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    List<User> users = sqlSession.selectList("test.findUserByUsername", "五");
    for (User user2 : users) {
        System.out.println(user2);  
    }
}

添加

<!-- 添加操作 -->
<insert id="insertUser" parameterType="com.pngyul.mybatis.pojo.User">
        insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
 @Test
 public void test() throws IOException {
      String resource="sqlMapConfig.xml";
      InputStream in=Resources.getResourceAsStream(resource);
      SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(in);
      SqlSession sqlSession=factory.openSession();  
      User user=new User();
      user.setUsername("pngyul");
      user.setBirthday(new Date()); 
      user.setSex("男");
      user.setAddress("广东");
      sqlSession.insert("test.insertUser", user);
      sqlSession.commit();
      sqlSession.close();
 }

添加并返回数据库自增主键

<!-- 保存用户 -->
<insert id="saveUser" parameterType="com.pngyul.mybatis.pojo.User">
    <!-- selectKey 标签实现主键返回 -->
    <!-- keyColumn:主键对应的表中的哪一列 -->
    <!-- keyProperty:主键对应的pojo中的哪一个属性 -->
    <!-- order:设置在执行insert语句前执行查询id的sql,还是在执行insert语句之后执行查询id的sql -->
    <!-- resultType:设置返回的id的类型 -->
    <!--LAST_INSERT_ID():是mysql的函数,返回auto_increment自增列新记录id值。-->
    <selectKey keyColumn="id" keyProperty="id" order="AFTER"
        resultType="Integer">
        SELECT LAST_INSERT_ID()
    </selectKey>
    INSERT INTO `user`
    (username,birthday,sex,address) VALUES
    (#{username},#{birthday},#{sex},#{address})
</insert
@Test
public void insertUser() throws Exception {
    String resource = "sqlMapConfig.xml";
    InputStream in = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    User user = new User();
    user.setAddress("广东");
    user.setBirthday(new Date());
    user.setSex("男");
    user.setUsername("ccfff");
    int i = sqlSession.update("test.insertUser", user);
    sqlSession.commit();
    System.err.println(user.getId());
    sqlSession.close();
    }

修改

<!-- 修改操作 -->
</update>
<delete id="deleteUserById" parameterType="Integer">
    delete from user where  id=#{id}
</delete>
@Test
public void updateUserById() throws Exception {
    String resource = "sqlMapConfig.xml";
    InputStream in = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    User user = new User();
    user.setAddress("广东");
    user.setBirthday(new Date());
    user.setSex("女");
    user.setUsername("ccfff");
    user.setId(30);
    int i = sqlSession.update("test.updateUserById", user);
    sqlSession.commit();
    sqlSession.close();
}

删除

<!-- 删除操作 -->
<delete id="deleteUser" parameterType="Integer">
    delete from user where id=#{id}
</delete>
@Test
public void test() throws IOException {
       String resource="sqlMapConfig.xml";
       InputStream in=Resources.getResourceAsStream(resource);
       SqlSessionFactoryBuilder builder= new SqlSessionFactoryBuilder();
       SqlSessionFactory factory=builder.build(in);
       SqlSession sqlSession=factory.openSession();  
       sqlSession.delete("deleteUser", 27);
       sqlSession.commit();
       sqlSession.close();
    } 

原始 Dao 开发方法

简单举个例子,了解一下即可

/1、编写mapper文件,并引入到核心配置文件中
<select id="findUserById" parameterType="Integer"
        resultType="User">
        select * from user where id = #{v}
</select>
//2、定义一个UserDao接口
public interface UserDao {
    User queryUserById(Integer id);
}
//3、UserDao实现类
package com.pngyul.mybatis.dao;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import com.pngyul.mybatis.pojo.User;

public class UserDaoImpl implements UserDao {
    private SqlSessionFactory sqlSessionFactory;


    public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
        super();
        this.sqlSessionFactory = sqlSessionFactory;
    }

    @Override
    public User queryUserById(Integer id) {
        SqlSession sqlsession = sqlSessionFactory.openSession();
        User user = sqlsession.selectOne("test.findUserById", id);
        sqlsession.close();
        return user;
    }
}
//测试
public class Junit {
    private SqlSessionFactory sqlSessionFactory;
    @Before
    public void init() throws Exception {
        // 创建SqlSessionFactoryBuilder
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        // 加载SqlMapConfig.xml配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 创建SqlsessionFactory
        this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
    }
    @Test
    public void testQueryUserById() {
        // 创建DAO
        UserDao userDao = new UserDaoImpl(this.sqlSessionFactory);
        // 执行查询
        User user = userDao.queryUserById(10);
        System.out.println(user);
    }

Mapper 动态代理方式

Mapper接口开发方法只需要程序员编写Mapper接口(相当于 Dao 接口),由 Mybatis 框架根据接口定义创建接口的动态代理对象。

Mapper接口开发需要遵循以下四个规范:

  • Mapper.xml 文件中的 namespace 与 mapper 接口的类路径相同,否则会找不到接口,也就无法生成代理对象。
  • Mapper 接口方法名和 Mapper.xml 中定义的每个方法的 id 相同
  • Mapper接口方法的输入参数类型和 mapper.xml 中定义的每个 sql 的 parameterType 的类型相同
  • Mapper 接口方法的输出参数类型和 mapper.xml 中定义的每个 sql 的 resultType 的类型相同

演示 Mapper 动态代理方式步骤:

1、编写Mapper文件 

<?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:命名空间,和Mapper接口的位置一样,这样框架会自动帮我们找到接口 --> 
<mapper namespace="com.pngyul.mybatis.mapper.UserMapper">
    <select id="findUserById" parameterType="int" resultType="com.pngyul.mybatis.pojo.User">
        select * from user where id =#{id}
    </select>

    <!-- 模糊查询 -->
    <select id="findUserByUsername" parameterType="String" resultType="com.pngyul.mybatis.mapper.UserMapper">
        <!-- ${}里面只能是value -->
        select * from user where username like '%${value}%'
    </select> 

    <!-- 添加操作 -->
    <insert id="insertUser" parameterType="com.pngyul.mybatis.mapper.UserMapper">
        insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
    </insert>

    <!-- 修改操作 -->
    <update id="updateUser" parameterType="com.pngyul.mybatis.mapper.UserMapper">
        update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
    </update>

    <!-- 删除操作 -->
    <delete id="deleteUser" parameterType="Integer">
        delete from user where id=#{id}
    </delete>
</mapper>
2、创建Mapper接口 

public interface UserMapper {
    public User findUserById(int id);
    public List<User> findUserByUsername(String username); 
    public void insertUser(User user); 
    public void deleteUser(Integer id);
}
3、核心配置文件中引入映射文件 

    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
4、测试  
public class MybatisTest {

    @Test
    public void test() throws IOException {
        String resource="sqlMapConfig.xml";
        InputStream in=Resources.getResourceAsStream(resource);
        SqlSessionFactoryBuilder builder= new SqlSessionFactoryBuilder();
        SqlSessionFactory factory=builder.build(in);
        SqlSession sqlSession=factory.openSession();  
        UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
        User user=userMapper.findUserById(1);
        System.out.println(user);
    } 
}

开发中使用这种方式来进行开发,简便快捷,代码复用性高,免去很多重复繁琐代码。

Mybatis 的 SqlMapConfig.xml 文件说明

MyBatis 的配置文件包含了 MyBatis 的设置和属性信息。文档的结构和顺序如下:

properties 属性
settings 设置
typeAliases 类型命名
typeHandlers 类型处理器
objectFactory 对象工厂
plugins 插件
environments(环境集合属性对象)
    environment(环境子属性对象)
        transactionManager(事务管理)
        dataSource(数据源)
databaseIdProvider 数据库厂商标识
mappers 映射器 

下面重点介绍几个:

properties(属性)

//db.peoperties文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
//引入文件
<properties resource="db.properties"/>
<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>

如果属性在不只一个地方进行了配置,那么 MyBatis 将按照下面的顺序来加载:

  • 在 properties 元素体内指定的属性首先被读取。
  • 然后根据 properties 元素中的 resource 属性读取类路径下属性文件或根据 url 属性指定的路径读取属性文件,并覆盖已读取的同名属性。

typeAliases(类型别名)

类型别名是为 Java 类型设置一个短的名字。它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余。

<typeAliases>
     <!-- 单个别名定义 -->
     <typeAlias alias="user" type="cn.cad.pojo.User" /> 
     <!-- 批量别名定义,扫描整个包下的类,别名为类名(大小写不敏感) -->
     <package name="cn.itcast.mybatis.pojo" />
     <package name="其它包" />
</typeAliases>

在mapper文件中就可以使用别名user。

Mybatis 已经为许多常见的 Java 类型内建了相应的类型别名。它们都是大小写不敏感的,例如 string,integer 等。

mappers(映射器)

映射器配置会告诉了 MyBatis 去哪里找映射文件。

<mapper resource=" " />:使用相对于类路径的资源(现在的使用方式)

<mapper url="file:///var/mappers/AuthorMapper.xml"/>:使用绝对路径,基本不会用 

<mapper class="cn.itcast.mybatis.mapper.UserMapper"/>:使用mapper接口类路径。注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。 

<package name="xxx"/>:注册指定包下的所有mapper接口,此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

PS::部分学习资料源于传智播客

猜你喜欢

转载自blog.csdn.net/PNGYUL/article/details/81805121