zoukankan      html  css  js  c++  java
  • 《深入浅出MyBatis技术原理与实战》——1.简介,2.入门

    1. 简介

    Java程序都是通过JDBC连接数据库,但是只定义了接口规范,具体的实现交给各个数据库厂商去实现,因为每个数据库都有其特殊性。所以JDBC是一种桥接模式

    这里为什么说JDBC是一种桥接模式呢?为例避免JDBC的缺陷出现了ORM模型,比如Hibernate,提供的是一种全表映射模型。因为Hibernate的一些缺陷,比如:

    • Hibernate屏蔽了SQL,只能全表映射,更新时需要发送所有的字段
    • 无法根据不同的条件组装不同的SQL
    • 对多表关联和复杂SQL查询支持较差,需要自己写SQL,返回后,需要自己将数据组装为POJO
    • 不能有效地支持存储过程
    • 虽然有HQL,但是性能较差。

    因此出现了MyBatis,一个半自动的框架。之所以称之为半自动,是因为它需要手动提供POJO、SQL和映射关系,而全表映射的Hibernate只需要提供POJO和映射关系即可,因为Hibernate无需编写SQL,所以开发效率优于MyBatis。

    2. MyBatis入门

    MyBatis的核心组件:

    • SqlSessionFactoryBuilder(构造器):它会根据配置信息或者代码来生成SqlSessionFactory(工厂接口)
    • SqlSessionFactory:依靠工厂来生成SqlSession
    • SqlSession:是一个既可以发送SQL去执行并返回结果,也可以获取Mapper的接口
    • SQL Mapper:它是MyBatis新设计的组件,是由一个java接口和XML文件(或注解)构成的,需要给出对应的SQL和映射规则。它负责发送SQL去执行,并返回结果。

    2.1 构建SqlSessionFactory

    每个MyBatis的应用都是以SqlSessionFactory的实例为中心,可以通过SqlSessionFactoryBuilder获得,注意SqlSessionFactory是一个工厂接口而不是实现类,其任务是创建SqlSession。SqlSession类似于一个JDBC的Connection对象。MyBatis提供了两种模式去创建SqlSessionFactory:一种是XML配置的方式,另一种是代码方式。要尽量的使用配置文件,这样一方面可以避免硬编码,一方面方便日后配置人员修改。

    org.apache.ibatis.session.Configuration在MyBatis中将以一个Configuration类对象的形式存在,存在于整个MyBatis应用的生命期中,以便重复读取和运用。我们可以一次性解析一次配置的XML保存到Configuration对象中。在MyBatis中提供了两个SqlSessionFactory的实现类,DefaultSqlSessionFactory和SqlSessionManager。目前使用的是DefaultSqlSessionFactory。

    2.1.1 使用XML方式构建

    这里以一个简易的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>
        <!--定义别名 -->
        <typeAliases>
            <typeAlias alias="role" type="com.learn.chapter2.po.Role"/>
        </typeAliases>
        <!--定义数据库信息,默认使用development数据库构建环境-->
        <environments default="development">  
            <environment id="development">  
                <!--采用jdbc事务管理 -->
                <transactionManager type="JDBC">
                    <property name="autoCommit" value="false"/>
                </transactionManager>
                <!--配置数据库链接信息  -->
                <dataSource type="POOLED">  
                    <property name="driver" value="com.mysql.jdbc.Driver" />  
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
                    <property name="username" value="root" />  
                    <property name="password" value="root" />
                </dataSource>  
            </environment>  
        </environments>  
        <!--定义映射器 -->
         <mappers>
             <mapper resource="com/learn/chapter2/mapper/roleMapper.xml"/>
         </mappers>
    </configuration>

    然后用代码实现创建SqlSessionFactory:

    String resource="mybatis-config.xml";
    InputStream inputStream=null;
    inputStream=Resources.getResourceAsStream(resource);
    sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);

    这里创建了一个XML文件输入流,用SqlSessionFactoryBuilder读取XML的信息 来创建SqlSessionFactory的对象。MyBatis的解析程序会将mybatis-config.xml文件配置信息解析到Configuration类对象里面,然后利用SqlSessionFactoryBuilder读取这个对象,为我们创建SqlSessionFactory。

    2.1.2 使用代码方式构建

    不推荐这种方式,因为修改环境的时候,要重新编译代码,不利于维护。

         //构建数据库连接池
            PooledDataSource dataSource=new PooledDataSource();
            dataSource.setDriver("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis");
            dataSource.setUsername("root");
            dataSource.setPassword("root");
            //构建数据库事务方式
            TransactionFactory transactionFactory=new JdbcTransactionFactory();
            //创建数据库运行环境
            Environment environment=new Environment("development",transactionFactory,dataSource);
            //构建Configuration对象
            Configuration configuration=new Configuration(environment);
            //注册一个MyBatis上下文别名
            configuration.getTypeAliasRegistry().registerAlias("role",Role.class);
            //加入一个映射器
            configuration.addMapper(RoleMapper.class);
            //使用SqlSessionFactoryBuilder构建SqlSessionFactory
            SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(configuration);
            return sqlSessionFactory;

    采用代码方式一般是需要加入自己特性的时候才会用到,例如数据源配置的信息要求是加密的时候,我们需要把它转化出来。大部分情况下不建议用这个方式来创建SqlSessionFactory

    2.1.2 创建SqlSession

    在MyBatis中SqlSession接口的实现类有两个,分别是DefaultSqlSession和SqlSessionManager。我们构建了SqlSessionFactory,然后生成门面接口SqlSession。SqlSession接口类似于一个JDBC中的Connection接口对象,我们需要保证每次用完正确关闭它。

    SqlSession的用途主要是获取映射器以及直接通过命名信息去执行SQL返回结果。

    2.1.3 映射器

    由Java接口和XML文件(或注解)共同组成,作用如下:

    • 定义参数类型
    • 描述缓存
    • 描述SQL语句
    • 定义查询结果和POJO的映射关系

    使用XML文件配置方式实现Mapper,第一步给出Java接口:

    public interface RoleMapper {
        public Role getRole(Long id);
        public int deleteRole(Long id);
        public int insertRole(Role role);
    }

    第二步给出一个映射文件:

    <?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.learn.chapter2.mapper.RoleMapper">
        <select id="getRole"  resultType="role" parameterType="long">
            select id,role_name as roleName,note from t_role where id=#{id}
        </select>
    </mapper>
    • MyBatis会读取这个配置文件,生成映射器
    • 定义一个命名空间为com.learn.chapter2.mapper.RoleMapper的SQL Mapper,这个命名空间和我们定义的接口的全限定名要一致
    • 用一个select元素定义一个查询SQL,id是getRole,和我们接口中的方法名是一致的
    • #{id}为这条SQL的参数。而SQL列的别名和POJO的属性名称保持一致。那么MyBatis就会把这条语句查询的结果自动映射到我们需要的POJO属性上

    现在可以使用SqlSession来获取这个Mapper:

    RoleMapper roleMapper=sqlSession.getMapper(RoleMapper.class);
    Role role=roleMapper.getRole(1L);

     2.1.4 Java注解方式实现Mapper

    不推荐注解的方式,如果系统简单的话,使用注解方式也不失为一个好办法。

    注册这个接口为映射器:

    2.1.4 一些疑问

    这要注意的是在MyBatis中保留这iBatis,通过命名空间+SQL id 的方式发送SQL并返回数据的形式,而不需要获取映射器:

    2.2 生命周期

    SqlSessionFactoryBuilder:只存在于方法的局部,作用是生成SessionFactory对象。

    SqlSessionFactory:存在于MyBatis应用的整个生命周期中,唯一责任是创建SqlSession,要采用单例模式。

    SqlSession:一个会话,相当于JDBC的一个Connection对象,他的生命周期应该是在请求数据库处理事务的过程中。它是一个线程不安全的对象。

    Mapper:一个接口,没有任何实现类,作用是发送SQL。因此它应该在一个SqlSession事务方法之内,是一个方法级别的东西。

    2.3 实例

    代码清单2-11:log4j.properties

    log4j.rootLogger=DEBUG, stdout
    log4j.logger.org=BEBUG
    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

     其中参数的解释见博文:http://www.cnblogs.com/alipayhutu/archive/2012/06/21/2558249.html 

    其次,构建SessionFactory,我们需要配置文件,代码:

    <?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 alias="role" type="com.learn.chapter2.po.Role"/>
        </typeAliases>
        <!--定义数据库信息,默认使用development数据库构建环境-->
        <environments default="development">  
            <environment id="development">  
                <!--采用jdbc事务管理 -->
                <transactionManager type="JDBC">
                    <property name="autoCommit" value="false"/>
                </transactionManager>
                <!--配置数据库链接信息  -->
                <dataSource type="POOLED">  
                    <property name="driver" value="com.mysql.jdbc.Driver" />  
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
                    <property name="username" value="root" />  
                    <property name="password" value="root" />
                </dataSource>  
            </environment>  
        </environments>  
        <!--定义映射器 -->
         <mappers>
             <mapper resource="com/learn/chapter2/mapper/roleMapper.xml"/>
         </mappers>
    </configuration>

     构建SqlSessionFactory

    package com.learn.chapter2.util;
    
    import java.io.InputStream;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    
    import org.apache.commons.logging.Log;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    public class SqlSessionFactoryUtil {
        //SqlSessionFactory对象
        private static SqlSessionFactory sqlSessionFactory=null;
        //类线程锁
        private static final Class Class_LOCK=SqlSessionFactoryUtil.class;
        /**
         * 私有化构造参数
         */
        private SqlSessionFactoryUtil(){}
        
        /**
         * 构建SqlSessionFactory
         */
        public static SqlSessionFactory initSqlSessionFactory(){
            String resource="mybatis-config.xml";
            InputStream inputStream=null;
            try{
                inputStream=Resources.getResourceAsStream(resource);
            }catch (Exception e) {
                Logger.getLogger(SqlSessionFactoryUtil.class.getName()).log(Level.SEVERE, null,e);
            }
            synchronized (Class_LOCK) {
                if(sqlSessionFactory==null){
                    sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
                }
            }
            return sqlSessionFactory;
        }
        /**
         * 打开SqlSession
         */
        public static SqlSession openSqlSession(){
            if(sqlSessionFactory==null){
                initSqlSessionFactory();
            }
            return sqlSessionFactory.openSession();
        }
    }

    上面要注意的部分:

    1. 类线程锁:private static final Class Class_LOCK=SqlSessionFactoryUtil.class;

    实现一个POJO类——Role.java

    package com.learn.chapter2.po;
    
    public class Role {
        private Long id;
        private String roleName;
        private String note;
        public Long getId() {
            return id;
        }
        public void setId(Long id) {
            this.id = id;
        }
        public String getRoleName() {
            return roleName;
        }
        public void setRoleName(String roleName) {
            this.roleName = roleName;
        }
        public String getNote() {
            return note;
        }
        public void setNote(String note) {
            this.note = note;
        }
    }

     还需要一个映射器的描述:

    <?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.learn.chapter2.mapper.RoleMapper">
        <select id="getRole"  resultType="role" parameterType="long">
            select id,role_name as roleName,note from t_role where id=#{id}
        </select>
        <insert id="insertRole" parameterType="role">
            insert into t_role(role_name,note) values (#{roleName},#{note})
        </insert>
        <delete id="deleteRole" parameterType="long">
            delete from t_role where id=#{id}
        </delete>
    </mapper>

     定义相应的接口:

    package com.learn.chapter2.mapper;
    
    import com.learn.chapter2.po.Role;
    
    public interface RoleMapper {
        public Role getRole(Long id);
        public int deleteRole(Long id);
        public int insertRole(Role role);
    }

     使用一个main方法来测试:

    package com.learn.chapter2.main;
    
    import org.apache.ibatis.session.SqlSession;
    
    import com.learn.chapter2.mapper.RoleMapper;
    import com.learn.chapter2.po.Role;
    import com.learn.chapter2.util.SqlSessionFactoryUtil;
    
    public class Chapter2Main {
        public static void main(String[] args){
            SqlSession sqlSession=null;
            try{
                sqlSession=SqlSessionFactoryUtil.openSqlSession();
                RoleMapper roleMapper=sqlSession.getMapper(RoleMapper.class);
                Role role=new Role();
                role.setRoleName("testName");
                role.setNote("testRole");
                roleMapper.insertRole(role);
                roleMapper.deleteRole(1L);
                sqlSession.commit();
            }catch (Exception e) {
                System.err.println(e.getMessage());
                sqlSession.rollback();
            }finally{
                if(sqlSession!=null){
                    sqlSession.close();
                }
            }
        }
    }
  • 相关阅读:
    [更新设计]跨平台物联网通讯框架ServerSuperIO 2.0 ,功能、BUG、细节说明,以及升级思考过程!
    有幸参加“集团2016年工业事业部发展规划会议”,向网友汇报!!!
    Centos7之ssh连接keepalive
    AES加密算法
    MySQL之only_full_group_by
    AES加解密文件流
    Mongo基本配置
    前端js处理接口返回的压缩包(亲测可用)
    Ubuntu20.4静态ip和dhcp配置
    Java数组类型协变性、泛型类型的不变性
  • 原文地址:https://www.cnblogs.com/f91og/p/7119129.html
Copyright © 2011-2022 走看看