zoukankan      html  css  js  c++  java
  • 预研报告——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;
    }
  • 相关阅读:
    由Kaggle竞赛wiki文章流量预测引发的pandas内存优化过程分享
    Python奇技淫巧 持续更新中....
    波士顿房价预测 最简单入门机器学习 Jupyter
    机器学习基本流程整理 这一篇就够啦
    阅读kaggle上大佬们的kernel
    wechat+项目开源分享 让你的微信账号有趣起来
    ✍36 PyQt5 模块错误排除
    ✍41 搭建wordpress&花生壳穿透
    ✍44.vs code远程编辑代码
    ✍42.图片识别相关cv2
  • 原文地址:https://www.cnblogs.com/564085446java/p/3607696.html
Copyright © 2011-2022 走看看