一、ORM 模型与 MyBatis

​ ORM:对象关系映射(Object Relation Mapping)

1、传统JDBC程序的设计缺陷

  1. 大量配置信息硬编码
  2. 大量的无关业务处理的编码
  3. 扩展优化极为不便

2、MyBatis概述

apache开源项目:ibatis(ibatis是internet和abatis的组合,一个基于javach持久层的框架)
2010年apache software foundation 》迁移google code(同年修改名称:MyBatis)
2013年 》google code 》迁移 》GitHub

MyBatis是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架。

  1. 避免传统JDBC硬编码
  2. XML配置或者注解
  3. POJO对象和数据库记录直接映射

二、MyBatis开发环境搭建

  • 获取MyBatis

官方网站:http://www.mybatis.org/mybatis-3

下载离线项目包:https://github.com/mybatis/mybatis-3/releases

  • 传统项目中使用MyBatis

    1. 下载地址
      https://github.com/mybatis/mybatis-3/releases
    2. 项目中引入
      引入 Jar 包。
  • maven方式引入

    <!-- MyBatis 3.4.3 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.3</version>
    </dependency>
    
    <!-- 同时需要引入使用的数据库 -->
    <!-- MySQL5.1.41 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.41</version>
    </dependency>
    

三、MyBatis 工作流程

1、MyBatis核心API操作过程分解

MyBatis 基础

2、Mybatis架构分解

MyBatis 基础

四、MyBatis 主要配置文件解析

1、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>
    <!-- 数据源配置,用于加载外部的properties配置文件 -->
    <properties resource="db.properties"></properties>
    
    <!-- 开发环境集合, 选择使用id为development的环境 -->
    <environments default="development">
        <!-- 开发环境 -->
        <environment id="development">
            <!-- 使用默认的JDBC事务管理 -->
            <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>
        <!-- 测试环境 -->
       	<environment id="test">
			...
        </environment>
        <!-- 生产环境 -->
       	<environment id="product">
			...
        </environment>
    </environments>
    
    
    <!-- mappers 主要用于配置我们的外部映射配置文件
	在主配置文件中需要引入加载映射配置文件  -->
    <mappers>
		 <!-- mapper 主要配置引入某一个具体的映射文件,resource进行路径方式引入 -->
        <mapper resource="mapper/usersMapper.xml"></mapper>
    </mappers>
</configuration>

2、数据源配置文件 db.properties

driver=com.mysql.jdbc.Driver
# 数据库使用UTF-8编码集、allowMultiQueries=true 使数据库允许批量更新
url=jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
username=root
password=root

3、Mapper 映射文件

​ 即根配置文件中配置的 mapper/usersMapper.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">
<!-- mapper 用于定义一个映射配置文件的根节点
     namespace属性用来配置命名空间,主要进行session级别的缓存管理
     命名空间默认情况下,使用我们当前操作的实体类的全路径 -->
<mapper namespace="com.moc.entity.Users">
    
    <!-- 使用动态SQL语句 ----- #{id} 是从传递的对象中获得的id属性 -->
    <!--  <select id="findUsers" resultType="com.moc.entity.Users">
		resultType与resultMap只能使用其中一个 -->
    <select id="findUsers" resultMap="forUsers">
        SELECT * FROM users
        <if test="id != null">
            WHERE id = #{id}
        </if>
    </select>

    <!-- 自定义映射关系集合:主要包含对于一些自定义操作的配置,
     如不一致的属性和字段  登录账号:username -> name  -->
    <resultMap id="forUsers" type="com.moc.entity.Users">
        <!-- 注意配置时的顺序	
			id标签绑定主键, 数据库的主键和实体类的主键进行绑定 -->
        <id property="id" column="id"/>
        
        <!-- result配置:主要配置普通属性,
        column表示配置的是数据库字段名称 property配置的是实体类的属性名称
 		默认数据库的字段名和实体的属性一致,不一致时配置 -->
        <result column="username" property="name"></result>
        
        <!-- 实体类的address属性(另外一个实体) 
		通过外键关联另一张表 再通过该表实体对应的SQL查询得到 -->
        <collection property="addresses" column="id" 
                    ofType="com.moc.entity.Address" select="getAddress"/>
    </resultMap>

    <!-- 采用resultType方式 -->
    <select id="getAddress" resultType="com.moc.entity.Address">
        SELECT * FROM address WHERE userid = #{id}
    </select>

    <!-- sql片段,用于简化,include标签引入 -->
    <sql id="user_fields">
        username, userpass, nickname, age, gender, email, phone, createTime, updateTime, lastLogin, userStatus, remark
    </sql>

    <!-- useGeneratedKeys:使用自动增长的这个值 
		keyProperty:将自动增长的这个值交给实体对象的id属性 -->
    <insert id="addUser" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO users( <include refid="user_fields"></include> )
        VALUES(#{name}, #{userpass}, #{nickname}, #{age}, #{gender}, #{email}, #{phone}, #{createTime}, #{updateTime}, #{lastLogin}, #{userStatus}, #{remark})
    </insert>

    <update id="updateUser">
        update users
        <set>
            <if test="name != null">username = #{name},</if>
			...
            <if test="remark != null">remark = #{remark},</if>
        </set>
        where id = #{id}
    </update>

    <delete id="delUser">
        delete from users where id = #{id}
    </delete>
</mapper>

五、基础操作实例

1、实体

  • 用户实体
public class Users {
    private Integer id;         // 用户编号
    //private String username;    // 登录账号
    private String name;        // 登录账号
    private String userpass;    // 登录密码
    private String nickname;    // 用户昵称
    private Integer age;        // 用户年龄
    private String gender;      // 用户性别
    private String phone;       // 联系方式
    private String email;       // 用户邮箱
    private Date createTime;    // 创建时间
    private Date updateTime;    // 账号最后修改时间
    private Date lastLogin;     // 用户最后修改时间
    private Integer userStatus; // 用户账号状态 0 正常 1 锁定 2 删除
    private String remark;      // 用户备注信息
    private List<Address> addresses;  // 用户地址信息【地址列表,存在一个默认地址】
    
    // 构造、set、get方法
    ......
}
  • 地址实体
public class Address {
    private Integer id;         // 编号
    private Users user;         // 所属用户
    private Boolean defaultAddr;  // 是否默认地址
    private String nation;      // 国家
    private String province;    // 省
    private String city;        // 市
    private String country;     // 县
    private String street;      // 街道
    private String remark;      // 描述
    
	// 构造、set、get方法
    ......
}

2、工具类 – MyBatisUtils

public class SqlSessionFactoryUtils {
    
    private static String RESOURCE = "mybatis-config.xml";
    private static SqlSessionFactory sqlSessionFactory;
    private static ThreadLocal<SqlSession> threadLocal = new 
				  ThreadLocal<SqlSession>();

    //** 创建一个初始化SqlSessionFactory的方法
    public static void initSqlSessionFactory() {
        try {
            InputStream is = Resources.getResourceAsStream(RESOURCE);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        } catch (IOException e) {
            System.out.println("初始化SqlSessionFactory失败....");
        }
    }
    //** 获取工厂对象的方法
    public static SqlSessionFactory getSqlSessionFactory() {
        return sqlSessionFactory;
    }
    //** 关闭SqlSession的方法
    public static void close() {
        SqlSession session = threadLocal.get();
        if (null != session) {
            session.close();
            threadLocal.set(null);
        }
    }
}

3、初始化 SqlSessionFactory

​ 在一启动 web 应用的时候,就应该调用上面 initSqlSessionFactory() 方法初始化SqlSessionFactory,应用程序结束的时候应关闭未关闭的SqlSession,这里采用 ServletContextListener 的方法进行管理。

// 监听器配置注解
@WebListener
public class InitSqlSessionListener implements ServletContextListener {
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("加载中....");
        // 初始化我们的SQLSessionFactory对象
        SqlSessionFactoryUtils.initSqlSessionFactory();
    }
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("销毁中....");
        // 关闭SQLSession对象
        SqlSessionFactoryUtils.close();
    }
}

4、DAO

public class UsersDAO {
    // sqlSession: MyBatis的关键对象,执行持久化操作的对象
    // 该对象底层封装了JDBC连接,其实例可直接执行已映射的SQL语句
    // SqlSession实例不能共享,也是线程不安全,不能将其放入静态字段或实例字段
   	// SqlSession实例应随用随获取,用完用finally确保关闭
    private SqlSession sqlSession;
    private List<Users> list;
    private Users user;

    //** 获取SQLSession
    private SqlSession getSqlSession() {
        sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession();
        return sqlSession;
    }

    //** 查询所有数据
    public List<Users> findAll() {
        try {
            list = getSqlSession().selectList("findUsers");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
        return list;
    }

    //** 根据编号查询单个用户
    public Users findAll(Integer id) {
        try {
            user = getSqlSession().selectOne("findUsers", new Users(id));
        } catch (Exception e) {
            System.out.println("根据编号查询单个用户失败 ...");
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
        return user;
    }

    //** 增加一个新用户数据到数据库的方法
    public Users addUser(Users user) {
        try {
            // 返回值:是insert执行过程中影响的行数
            getSqlSession().insert("addUser", user);
            // 影响数据库的操作 需要进行提交才能生效
            sqlSession.commit();  
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
        return user;
    }

    //** 用于修改用户资料的方法
    public Users updateUsers(Users user) {
        try {
            // 返回值:是insert执行过程中影响的行数
            getSqlSession().update("updateUser", user);
            sqlSession.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
        return user;
    }

    //** 用于删除用户的方法
    public void delUsers(Integer id) {
        try {
            // 返回值:是delete执行过程中影响的行数
            getSqlSession().delete("delUser", id);
            sqlSession.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
    }
}

5、 业务 CRUD

private UsersDAO usersDAO = new UsersDAO();

// 插入用户数据
Users user = new Users(...);
user = usersDAO.addUser(user);

// 删除用户数据
usersDAO.delUsers(Integer.parseInt(id));

// 动态SQL 查找单个用户
Users user = usersDAO.findAll(Integer.parseInt(id));

// 查找全部用户
List<Users> list = usersDAO.findAll();

// 更新用户
usersDAO.updateUsers(user);

相关文章: