预研报告——MyBatis持久层的demo

一、预研任务介绍和预研目标

任务介绍:

与 Hibernate 相比, MyBatis 是一个半自动化的持久层框架,以轻量级、效率高、原生代而好评如潮。虽然有在分享会上大致讲解,但是还是重新梳理成文字,方便后来人查阅。

预研目标:

编写并讲解 MyBatis 与持久层结合的 demo ,实际应用起这门新技术。

二、操作步骤

1. jar 包准备

 

备注:mybatis.jar是mybatis的核心,mybatis-spring是mybatis团队出品的mybatis整合spring工具包。

2.  准备工作

) 在数据库(MySQL )上的 test 数据库新建如下表格并添加测试数据:

CREATE TABLE sys_employees (

  emp_id INT(11) NOT NULL AUTO_INCREMENT,

  emp_name VARCHAR(255) NULL DEFAULT NULL COMMENT '员工名称',

  emp_password VARCHAR(255) NULL DEFAULT NULL COMMENT '员工密码',

  emp_email VARCHAR(255) NULL DEFAULT NULL COMMENT '员工邮件',

  emp_desc VARCHAR(255) NULL DEFAULT NULL COMMENT '员工描述',

  emp_account VARCHAR(255) NULL DEFAULT NULL COMMENT '员工账户',

  is_sys BOOL NULL DEFAULT '0' COMMENT '是否管理员 0:否 1:是',

  is_using BOOL NULL DEFAULT '1' COMMENT '是否在职 0:否 1:是',

  PRIMARY KEY(emp_id)

)

ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;Insert into sys_employees values(null, 'jayzee', '123456', null, null, 'jayzee', 0, 1);Insert into sys_employees values(null, 'nikey', '123456', null, null, 'jayzee', 0, 1); 

)  新建一个简单的java项目 Pro 4 - MyBatisDemo,在其 build path 下新建一个source folder 名为 resources 专门放配置文件,在resources文件夹 下编写如下文件( generator.xml )并使用 mybatis generator 插件  [1]生成 model 类、 mapper 接口及 xml 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
  PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <!-- classPathEntry:数据库的JDBC驱动 -->
    <classPathEntry
        location="/home/jayzeee/Documents/Java/Jars/mysql/mysql-connector-java-5.1.17-bin.jar" />

    <context id="MySQLTables" targetRuntime="MyBatis3">
        <!-- 去除自动生成的注释 -->
        <commentGenerator>
            <property name="suppressAllComments" value="true" />
        </commentGenerator>

        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
            connectionURL="jdbc:mysql://localhost:3306/test" userId="root"
            password="123456">
        </jdbcConnection>

        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

        <!-- targetProject:自动生成代码的位置 -->
        <javaModelGenerator targetPackage="com.nikey.oa.model.Demo"
            targetProject="Pro 4 - MyBatisDemo">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>

        <sqlMapGenerator targetPackage="com.nikey.oa.mapper.Demo"
            targetProject="Pro 4 - MyBatisDemo">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>

        <javaClientGenerator type="XMLMAPPER"
            targetPackage="com.nikey.oa.mapper.Demo" targetProject="Pro 4 - MyBatisDemo">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>

        <!-- tableName:用于自动生成代码的数据库表;domainObjectName:对应于数据库表的javaBean类名 -->
        <table tableName="sys_employees" domainObjectName="Employee" />
        

    </context>

</generatorConfiguration>

) 删除自动生成的 Employee-example.java  EmployeeMapper.java 里面的所有方法; EmployeeMapper.xml  <resultMap> 之后的文本全部不要(自动生成的这些东西太冗杂了,我们完全无用,自己的才是最合适的)。还有 一个建议,最好在resources下面新建一个与 src存放mapper 相同的包名把把 EmployeeMapper.xml迁移过去(后面会解释为什么这么做)。目前包结构如下:

4) 在 resources 下添加 log4j.properties ,开启 mybatis 后台信息打印,内容如下:

# Rules reminder:

# DEBUG < INFO < WARN < ERROR < FATAL

 

# Global logging configuration

log4j.rootLogger=DEBUG, stdout

 

# My logging configuration...

log4j.logger.org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl=stdout

 

## Console output...

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern=%5p %d %C: %m%n

3. 整合 Spring

1) resources 下新建 spring 文件夹,并新建 applicationContext.xml ,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!--
    Copyright 2013 Nikey
    Author Jayzee
    Created 2013-08-04
-->

<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:aop="http://www.springframework.org/schema/aop"
     xmlns:tx="http://www.springframework.org/schema/tx"
     xmlns:context="http://www.springframework.org/schema/context"
     xsi:schemaLocation="
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <!-- 启用autowire -->
    <context:annotation-config />

    <!-- 启用spring注解扫描并指定包所在的位置 -->    
    <context:component-scan base-package="*" />

    <!--配置apache dbcp数据源 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url"
            value="jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=utf8" />
        <property name="username" value="root" />
        <property name="password" value="123456" />
        <!-- 连接池启动时的初始值 -->
        <property name="initialSize" value="7" />
        <!-- 连接池的最大值 -->
        <property name="maxActive" value="20" />
        <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
        <property name="maxIdle" value="7" />
        <!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
        <property name="minIdle" value="2" />
    </bean>

    <!-- 使用事务管理器管理数据源 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    
    <!-- 启用事务注解,使用@Transactional注解 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    <!-- 定义mybatis的sqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!-- 以每个类的类名作为该类的别名,如Employee等同于com.nikey.oa.model.Demo.Employee -->
        <property name="typeAliasesPackage" value="com.nikey.oa.model" />
        <!--configLocation属性指定mybatis的核心配置文件-->
         <property name="configLocation" value="classpath:mybatis/configuration.xml"/>
    </bean>
    
    <!-- sqlsessiontemplate模板,主要用于测试 -->
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory" />
    </bean>

    <!-- 扫描mybatis的mappers并让他们自动注入,
  为什么上面建议放配置文件的包名与放接口的包名一致,是因为这个扫描器会把xml和interface一起扫描,并将xml的内容作为interface的实现类 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.nikey.oa.mapper" />
    </bean>
</beans>

2) mybatis核心配置文件配置

<?xml version="1.0" encoding="utf8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
  
  <!-- 配置全局设置,参照API -->
  <settings>        
      <!-- 开启batch -->
    <setting name="defaultExecutorType" value="BATCH" />
  </settings>
 
  <!-- 配置别名,已在spring配置,无需重复配置 --> 
  <!-- <typeAliases>
      <typeAlias alias="Employee" type="com.nikey.oa.model.Employee"/>
  </typeAliases> -->

  <!-- 由于已在spring配置文件里扫描mappper,无需重复配置 -->
  <!-- <mappers>
    <mapper resource="classpath:com/nikey/oa/mapper/Demo/EmployeeMapper.xml"/>
  </mappers> -->

  <!-- 添加对一些特殊类型的处理,详情参照API -->
  <typeHandlers>
      <typeHandler handler="org.apache.ibatis.type.BooleanTypeHandler" javaType="Boolean" jdbcType="BIT"/>
      <typeHandler handler="org.apache.ibatis.type.BlobTypeHandler" javaType="byte[]" jdbcType="BLOB"/>
  </typeHandlers>

</configuration>

3) mybatis的核心,mapper(即dao)的讲解以及使用

首先,打开EmployeeMapper.java,修改内容如下:

package com.nikey.oa.mapper.Demo;

import com.nikey.oa.model.Demo.Employee;

/**
 * @author jayzeee
 *
 */
public interface EmployeeMapper {/**
     * @param employee
     * @return 根据查询返回一个雇员
     */
    Employee getAnEmployee(Employee employee);

}

其次,修改EmployeeMapper.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="com.nikey.oa.mapper.Demo.EmployeeMapper" >
  
  <!-- id表示主键,result表示普通字段,column与数据库字段名对应,property与javabean的属性对应,type是javabean名字,其实我们这里我们已经使用了别名,
  它的全名是com.nikey.oa.model.Demo.Employee -->
  <resultMap id="BaseResultMap" type="Employee" >
    <id column="emp_id" property="empId" jdbcType="INTEGER" />
    <result column="emp_name" property="empName" jdbcType="VARCHAR" />
    <result column="emp_password" property="empPassword" jdbcType="VARCHAR" />
    <result column="emp_email" property="empEmail" jdbcType="VARCHAR" />
    <result column="emp_desc" property="empDesc" jdbcType="VARCHAR" />
    <result column="emp_account" property="empAccount" jdbcType="VARCHAR" />
    <result column="is_sys" property="isSys" jdbcType="BIT" />
    <result column="is_using" property="isUsing" jdbcType="BIT" />
  </resultMap>
  
  <!-- sql块,方便重用 -->
  <sql id="employee">
      E.emp_id, E.emp_name, E.emp_password, E.emp_email, E.emp_desc, E.emp_account, E.is_sys, E.is_using
  </sql>
  
  <!-- id与方法同名,parameterType表示传进来的参数(可以不写让mybatis自动判断),resultmap表示返回的结果集,
  我们可以自己灵活组织结果集,学mybatis实际就是在写sql和组织resultmap -->
  <select id="getAnEmployee" parameterType="Employee" resultMap="BaseResultMap">
      select 
      <!-- 引用sql块 -->
      <include refid="employee"/>
      from sys_employees E
      <!-- 动态判断,不为空则加入where后面,where有自动去除and的功能,所以不用担心语句出错 -->
    <where>  
      <if test="empId !=null ">  
          E.emp_id = #{empId}
      </if>
      <if test="empName !=null and empName != '' ">  
          and E.emp_name = #{empName}
      </if>
      <if test="empPassword !=null and empPassword != '' ">  
          and E.emp_password = #{empPassword}
      </if>
    </where>
  </select>
  
</mapper>

4)测试

首先,在build path下新建source文件夹test,并在test下新建包名:com.nikey.oa.mapper.Demo

其次,我们在该包下建一个SqlSessionTemplateTest.java,内容如下:

package com.nikey.oa.mapper.Demo;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.nikey.oa.model.Demo.Employee;

/**
 * @author jayzeee
 *
 */
public class SqlSessionTemplateTest {public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
        SqlSessionTemplate sqlSessionTemplate = (SqlSessionTemplate) context.getBean("sqlSessionTemplate");
        
        //使用sqlSessionTemplate调用mapper里的方法,语法:无需指定mapper,直接在参数里填方法名,因为这个方法名是全局的
        Employee e = new Employee();
        e.setEmpName("jayzee");
        Employee employee = sqlSessionTemplate.selectOne("getAnEmployee", e);
        System.out.println(employee);
    }

}

打印结果:com.nikey.oa.model.Demo.Employee@1d5e5d7

至此,我们的包结构如下:

如果你想开启mybatis的缓存机制,需要加入如下两个配置:

配置1:在EmployeeMapper.xml下添加<cache>

配置2:系列化Employee.java

入门讲解到此为止,下面讲解mybatis的高级部分

4.灵活传参以及resultmap的组织

1) 准备工作

在本地的mysql的test数据库下运行下面的语句:

CREATE TABLE sys_roles (
  role_id INT(11) NOT NULL AUTO_INCREMENT,
  role_name VARCHAR(255) NULL DEFAULT NULL COMMENT '角色名称',
  role_desc VARCHAR(255) NULL DEFAULT NULL COMMENT '角色描述',
  is_enable BOOL NULL DEFAULT '1' COMMENT '是否启用 0:否 1:是',
  is_sys BOOL NULL DEFAULT '0' COMMENT '是否管理员 0:否 1:是',
  PRIMARY KEY(role_id)
)
ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;CREATE TABLE sys_employees_roles (
  emp_id INT(11) NOT NULL COMMENT '员工',
  role_id INT(11) NOT NULL COMMENT '角色',
  PRIMARY KEY(emp_id, role_id),
  INDEX emp_id_index(emp_id),
  INDEX role_id_index(role_id),
  FOREIGN KEY(emp_id)
    REFERENCES sys_employees(emp_id)
      ON DELETE NO ACTION
      ON UPDATE CASCADE,
  FOREIGN KEY(role_id)
    REFERENCES sys_roles(role_id)
      ON DELETE NO ACTION
      ON UPDATE CASCADE
)
ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;CREATE TABLE departments (
  depart_id INT(11) NOT NULL AUTO_INCREMENT,
  depart_name VARCHAR(255) NULL DEFAULT NULL COMMENT '部门名称',
  depart_desc VARCHAR(255) NULL DEFAULT NULL COMMENT '部门描述',
  PRIMARY KEY(depart_id)
)
ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;CREATE TABLE departments_employees (
  emp_id INT(11) NOT NULL COMMENT '员工',
  depart_id INT(11) NOT NULL COMMENT '部门',
  PRIMARY KEY(emp_id, depart_id),
  INDEX depart_id_index(depart_id),
  INDEX emp_id_index(emp_id),
  FOREIGN KEY(depart_id)
    REFERENCES departments(depart_id)
      ON DELETE NO ACTION
      ON UPDATE CASCADE,
  FOREIGN KEY(emp_id)
    REFERENCES sys_employees(emp_id)
      ON DELETE NO ACTION
      ON UPDATE CASCADE
)
ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;insert into sys_roles values (4, '技术工程师', '小弟', 1, 0);insert into sys_roles values (5, '软件工程师', '小弟', 1, 0);insert into sys_employees_roles values (1, 4);insert into sys_employees_roles values (1, 5);insert into departments values (1, '软件部', '做软件的');insert into departments_employees values (1, 1);

修改generator.xml底部内容如下:

<!-- tableName:用于自动生成代码的数据库表;domainObjectName:对应于数据库表的javaBean类名 -->
<table tableName="sys_roles" domainObjectName="Role" />
<table tableName="departments" domainObjectName="Department" />

参照上文删除-example.java文件和清除接口以及xml的无用信息

在Employee.java下添加如下信息:

private List<Role> roles;
    
private Department department;

public Department getDepartment() {
    return department;
}

public void setDepartment(Department department) {
    this.department = department;
}

public List<Role> getRoles() {
    return roles;
}

public void setRoles(List<Role> roles) {
    this.roles = roles;
}
posted @ 2014-03-18 14:44  简简-单单  阅读(797)  评论(0编辑  收藏  举报