• MyBatis 学习笔记


    MyBatis 学习笔记:
    官网: http://www.mybatis.org , http://code.google.com/p/mybatis/

    =========================
    用到的资料和工具:  
    =========================
    1. 从官网下载用户手册:  MyBatis 3 User Guide Simplified Chinese.pdf
    2. 几个主要的参考教程:
       mybatis3入门学习笔记 (五star推荐, 我直接使用了该作者的SessionFactoryUtil类)
       http://blessht.iteye.com/blog/1097005   
       
       有关 sql xml 的写法, 可以参考下面2个文章, 讲的很清晰
       cms项目第9天(上)-mybatis框架
       http://blog.sina.com.cn/s/blog_6bcb0a8c0100q6ub.html
       cms项目第9天(下)-mybatis框架
       http://blog.sina.com.cn/s/blog_6bcb0a8c0100q6ud.html
       
    3. 下载MyBatis最新的运行包, mybatis-3.0.6-bundle.zip
    4. 下载MyBatis最新的代码生成工具包, mybatis-generator-core-1.3.1-bundle.zip
    5. 下载MyBatis的config和map以及mybatis-generator的DTD文件.
        mybatis 仍使用过时的DTD作为XML的schema, 我们写的XML每个标签必须按照DTD中的声明顺序写,不然会报XML invalidated错误. 不知道MyBatis为什么不用XSD来代替DTD?
        http://mybatis.org/dtd/mybatis-3-config.dtd
        http://mybatis.org/dtd/mybatis-3-mapper.dtd
        http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd
    6. 准备Eclipse XML Editor插件(Visual studio仅仅支持xsd, 不支持dtd), 每次在Eclipse要安装这个插件, 总是花好长时间来google找个插件的名称, 这次将安装过程记录下来.
       在Eclipse的菜单Install new software中, 选择下面的site:
          Indigo - http://download.eclipse.org/releases/indigo
       然后选择  Web, XML, Java EE and OSGi Enterprise Development    
       最后选择  Eclipse XML Editors and Tools
       

    =========================
    使用 mybatis-generator 根据table, 可生成 POJO/SQL map XML和DAO mapper代码,
    注意: 该工具并不负责生成 mybatis 主config 文件.
    =========================   
    要使用mybatis-generator工具, 首先需要手动写一个generator的配置文件, 可以参考 mybatis-generator-core-1.3.1-bundle.zip包里的文档, 假定我们已经写好了名为generatorConfig.xml的配置文件 , 使用mybatis-generator方法是:
     
    1. 首次生成POJO/DAO Interface/xml mapping的命令,
      java -jar mybatis-generator-core-x.x.x.jar -configfile generatorConfig.xml -overwrite  
    2. 如有几个表重构结构后, 可以使用如下命令, 重新生成相关的 POJO/DAO Interface/xml mapping文件,
      java -jar mybatis-generator-core-x.x.x.jar -configfile generatorConfig.xml -overwrite   -tables  table1,table2,table3
     
    以下是一个mybatis-generator配置文件的内容,
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "../res/mybatis-generator-config_1_0.dtd">

    <generatorConfiguration>
        <classPathEntry
            location="D://corp_files/trunk/workspace/MyProject/lib/postgresql-9.1-901.jdbc4.jar" />

        <context id="MyProject" targetRuntime="MyBatis3" >
            
            <commentGenerator>
                 <property name="suppressAllComments" value="true" />
            </commentGenerator>

            <jdbcConnection driverClass="org.postgresql.Driver"
                connectionURL="jdbc:postgresql://localhost:5432/postgres" userId="postgres"
                password="abc123!">
            </jdbcConnection>

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

            <javaModelGenerator targetPackage="MyProject.model"
                targetProject="c:/src">
                <property name="enableSubPackages" value="true" />
                <property name="trimStrings" value="false" />
            </javaModelGenerator>

            <sqlMapGenerator targetPackage="MyProject.xml"
                targetProject="c:/src">
                <property name="enableSubPackages" value="true" />
            </sqlMapGenerator>

            <javaClientGenerator type="XMLMAPPER"
                targetPackage="MyProject.dao" targetProject="c:/src">
                <property name="enableSubPackages" value="true" />
            </javaClientGenerator>
            
            
            <table tableName="user_info" schema="public" domainObjectName="UserBean">
            </table>
            <table tableName="dept_info" schema="public" domainObjectName="DeptBean">
            </table>

        </context>
    </generatorConfiguration>

     


    =========================
    编写mybatis config 文件:  
    =========================
    基本作用就是配置JDBC连接的有关信息,比如URL、用户名、密码等等, 下面的配置文件是从网上拷贝了一份.
    <?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>
            <typeAlias type="org.leadfar.mybatis.Person" alias="Person" />
        </typeAliases>

        <!-- 配置数据库连接信息 -->
        <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/mybatis" />
                    <property name="username" value="root" />
                    <property name="password" value="leadfar" />
                </dataSource>
            </environment>

        </environments>

        <!-- 映射文件定位 -->
        <mappers>
            <mapper resource="org/leadfar/mybatis/PersonMapper.xml" />
        </mappers>

    </configuration>

     


    =========================
    使用 mybatis-generator 生成 POJO/SQL map XML和DAO mapper代码
    =========================
    首先看一下生成的代码,  POJO很简单, 就不贴了,

    生成的 DAO interface(有删减)
    public interface cronMapper {
        int deleteByPrimaryKey(String cronCode);
        //....
    }


    生成的 sql mapping 配置文件(有删减)
    <?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="MyProject.dao.public.cronMapper" >
    <delete id="deleteByPrimaryKey" parameterType="java.lang.String" >
     
        delete from public.caw_cron
        where cron_code = #{cronCode,jdbcType=VARCHAR}
      </delete>
    </mapper>  


    从上面看出, 生成的 DAO 代码其实都是 interface (如cronMapper), 而不是具体的 class, 那么现在就有一个疑问了, 我们该如何使用这个接口呢? 是否需要自己写代码来实现该接口呢?

    答案是, 不需要! 我们直接使用 MyBatis的 SqlSession的 getMapper()方法就可以动态的获得一个已经实现了 cronMapper 接口的对象. 见下面的代码,   

    如何使用 cronMapper 接口, 进行DAO 操作,
    SqlSession session = sqlSessionFactory.openSession();
    try {
        cronMapper mapper = session.getMapper(cronMapper.class);
        mapper.deleteByPrimaryKey("your_code")
        // do other work
    } finally {
        session.close();
    }


    至于MyBatis的 SqlSession的 getMapper(), 为什么能为我们返回一个实现 cronMapper 接口的对象, 应该是使用了JDK的动态代理或者拦截技术吧.

    在知道了如何使用 MyBatis 生成的 DAO 接口代码后, 还有一个问题是, 是否还需要自己的DAO代码层? 我觉得仍然需要, 原因有两个:
    1. 如果直接在Business Logic层(BLL)使用 Mybatis的sqlSessionFactory.openSession(), BLL代码显得不太简洁, 如果我们在自己的的DAO层封装了openSession()代码, BLL层代码就简洁多了.
    2. 很多时候我们的查询会复杂一些, 比如在权限管理模块, 一个用户对象可以有多个角色对象. 我们期望的方案是, 在用户对象内部有一个角色对象集合. MyBatis 可通过 resultMap 支持这种 one-to-many 的 mapping, 其后果是sql mapping 的xml要复杂很多. 我个人觉得, 这种情况, 不如不用mybatis这些高级特性, MyBatis仅仅完成UserEntityDAO和RoleEntityDAO的简单mapping, 然后自己实现一个User DAO对象, 将UUserEntityDAO和RoleEntityDAO在代码中做封装.  


    =========================
    可以将MyBatis的sqlSessionFactory和 getSession()封装在一个工具类中. 这样自定义的DAO类可能很方便地使用.
    摘自 http://blessht.iteye.com/blog/1097005  
    =========================
    public class SessionFactoryUtil {  
        
        private static final String RESOURCE = "com/mybatisdemo/config/Configuration.xml";  
        private static SqlSessionFactory sqlSessionFactory = null;  
        private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>();  
     
        static {  
            Reader reader = null;  
            try {  
                reader = Resources.getResourceAsReader(RESOURCE);  
            } catch (IOException e) {  
                throw new RuntimeException("Get resource error:"+RESOURCE, e);  
            }  
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);  
        }  
          
        /**
         * Function  : 获得SqlSessionFactory
         */  
        public static SqlSessionFactory getSqlSessionFactory(){     
            return sqlSessionFactory;     
        }  
          
        /**
         * Function  : 重新创建SqlSessionFactory
         */  
        public static void rebuildSqlSessionFactory(){  
            Reader reader = null;  
            try {  
                reader = Resources.getResourceAsReader(RESOURCE);  
            } catch (IOException e) {  
                throw new RuntimeException("Get resource error:"+RESOURCE, e);  
            }  
     
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);  
        }  
          
        /**
         *  
         * Function  : 获取sqlSession
         */  
        public static SqlSession getSession(){  
            SqlSession session = threadLocal.get();  
              
            if(session!=null){  
                if(sqlSessionFactory == null){  
                    getSqlSessionFactory();  
                }  
                //如果sqlSessionFactory不为空则获取sqlSession,否则返回null  
                session = (sqlSessionFactory!=null) ? sqlSessionFactory.openSession(): null;  
            }  
              
            return session;  
        }  
          
        /**
         * Function  : 关闭sqlSession
         */  
        public static void closeSession(){  
            SqlSession session = threadLocal.get();  
            threadLocal.set(null);  
            if(session!=null){  
                session.close();  
            }  
        }  
    }  


    =========================
    问题1: 如何mapping 数据表的char(1)和java 的 boolean类型
    摘自 http://javaeenotes.blogspot.com/2011/10/mybatis-and-oracle-database.html (通过bing 搜索引擎可以看到cache)
    =========================

    针对这种需求, 在SQL XML中, 不能直接使用resultType, 必须有个resultMap, 在对应的boolean字段节点上, 指定typeHandler.
    <resultMap id="BaseResultMap" type="MyProject.model.public.cron" >
        <!--
          WARNING - @mbggenerated
          This element is automatically generated by MyBatis Generator, do not modify.
          This element was generated on Wed Nov 30 17:34:29 CST 2011.
        -->
        <id column="job_code" property="jobCode" jdbcType="VARCHAR" />
        <result column="enabled" property="enabled" jdbcType="CHAR" typeHandler="com.xxx.sample.BooleanTypeHandler" />
        <result column="description" property="description" jdbcType="VARCHAR" />
      </resultMap>
     
     
     
    实现一个com.xxx.sample.BooleanTypeHandler类,
    import org.apache.ibatis.type.JdbcType;  
    import org.apache.ibatis.type.TypeHandler;  

    /**
     * BooleanTypeHandler类, 处理完成char(1)与Boolean类型的转换
     */
    public class BooleanTypeHandler implements TypeHandler<Boolean>
    {
        private static final String YES = "Y";  
        private static final String NO = "N";  
        
        private Boolean valueOf(String value) throws SQLException
        {
            if (YES.equalsIgnoreCase(value))
                return new Boolean(true);
            else
                return new Boolean(false);
        }
     
        @Override
        public Boolean getResult(ResultSet resultSet, String name) throws SQLException
        {
            return valueOf(resultSet.getString(name));
        }

        @Override
        public Boolean getResult(CallableStatement statement, int position) throws SQLException
        {
            return valueOf(statement.getString(position));  
        }
     
        @Override
        public void setParameter(PreparedStatement statement, int position, Boolean value, JdbcType jdbcType) throws SQLException
        {
            statement.setString(position, value.booleanValue() ? YES : NO);  
        }

    }

    =========================
    问题2: Insert语句中, 如何使用Oracle的sequence对象
    摘自 http://javaeenotes.blogspot.com/2011/10/mybatis-and-oracle-database.html (通过bing 搜索引擎可以看到cache)
    =========================
    Unlike other databases like MySQL, the Oracle database does not provide the functionality to generate primary keys automatically when inserting rows.
        public interface ClientMapper {  
          @Insert("INSERT INTO client (id, name) VALUES (#{id}, #{name})")  
          @SelectKey(  
                    keyProperty = "id",  
                    before = true,  
                    resultType = Integer.class,  
                    statement = { "SELECT client_seq.nextval AS id FROM dual" })  
          public Integer insertClient(Client client);  
        }  
        
        
        
    =========================
    最后, 列出几个不错的参考文章
    =========================
       mybatis3入门学习笔记 (五star推荐)
       http://blessht.iteye.com/blog/1097005   
       
       有关 sql xml 的写法, 可以参考下面2个文章, 讲的很清晰
       cms项目第9天(上)-mybatis框架
       http://blog.sina.com.cn/s/blog_6bcb0a8c0100q6ub.html
       cms项目第9天(下)-mybatis框架
       http://blog.sina.com.cn/s/blog_6bcb0a8c0100q6ud.html

       MyBatis+Spring基于接口编程的原理分析
       http://denger.iteye.com/blog/1060588
        
       MyBatis 缓存机制深度解剖 / 自定义二级缓存
       http://denger.iteye.com/blog/1126423
       
       使用Mybatis Generator自动生成Mybatis相关代码
       http://qiuguo0205.iteye.com/blog/819100      
       
       log4jdbc 日志框架介绍, 因为mybatis基本上是使用preparedStatement, 所以打出的日志, sql和参数值是分开的, 可读性不好, log4jdbc 可以解决这个问题.  
       http://badqiu.iteye.com/blog/743100
       http://indure.chinaunix.com/space.php?uid=78707&do=blog&id=1631151
       官网:http://code.google.com/p/log4jdbc/wiki/FAQ

       几个个英文教程, 写得还算可以吧.
       http://javaeenotes.blogspot.com/2011/10/mybatis-and-oracle-database.html (通过bing 搜索引擎可以看到cache)
       http://mybatis.co.uk/index.php/2010/09/mybatis-simple-and-complete-example.html
       http://blog.idleworx.com/2010/06/idleworxs-mybatis-tutorials.html
      

  • 相关阅读:
    linux svn切换用户
    解决QQ“抱歉,无法发起临时会话,您可以 添加对方为好友以发送消息”
    node.js中http.respone.end方法概述
    niginx:duplicate MIME type "text/html" in nginx.conf 错误(转载)
    大三暑假实习,我们可以怎么做
    一个Java程序员的实习总结(2)
    正式工作的前奏——一个Java程序员的实习总结(1)
    【个人】当我秀智商的时候我秀什么
    基于java的设计模式入门(1)——为什么要学习设计模式
    【个人】我不愿让你一个人
  • 原文地址:https://www.cnblogs.com/harrychinese/p/learn_mybatis.html
Copyright © 2020-2023  润新知