Mybatis教程之Mybatis配置篇

1. 说明:

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。

什么意思,看下例子,原生的jdbc案例:

//STEP 1. Import required packages
import java.sql.*;

public class FirstExample {
   // JDBC driver name and database URL
   static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";  
   static final String DB_URL = "jdbc:mysql://localhost/emp";

   //  Database credentials
   static final String USER = "root";
   static final String PASS = "123456";

   public static void main(String[] args) {
   Connection conn = null;
   Statement stmt = null;
   try{
      //STEP 2: Register JDBC driver
      Class.forName("com.mysql.jdbc.Driver");

      //STEP 3: Open a connection
      System.out.println("Connecting to database...");
      conn = DriverManager.getConnection(DB_URL,USER,PASS);

      //STEP 4: Execute a query
      System.out.println("Creating statement...");
      stmt = conn.createStatement();
      String sql;
      sql = "SELECT id, first, last, age FROM Employees";
      ResultSet rs = stmt.executeQuery(sql);

      //STEP 5: Extract data from result set
      while(rs.next()){
         //Retrieve by column name
         int id  = rs.getInt("id");
         int age = rs.getInt("age");
         String first = rs.getString("first");
         String last = rs.getString("last");
      }
      //STEP 6: Clean-up environment
      rs.close();
      stmt.close();
      conn.close();
   }catch(SQLException se){
      //Handle errors for JDBC
      se.printStackTrace();
   }catch(Exception e){
      //Handle errors for Class.forName
      e.printStackTrace();
   }finally{
      //finally block used to close resources
      try{
         if(stmt!=null)
            stmt.close();
      }catch(SQLException se2){
      }// nothing we can do
      try{
         if(conn!=null)
            conn.close();
      }catch(SQLException se){
         se.printStackTrace();
      }//end finally try
   }//end try
   System.out.println("There are so thing wrong!");
}//end main
}//end FirstExample

原生的jdbc 代码阅读困难, 耦合性强,复用能力查,设计模式粗糙。为了将这个过程格式化或者说是模板话,便出来了好多工具。

例如:DBUtil, Mybaitis, Hibernate

接下来我们就介绍下Mybatis的使用方式。

1. 项目依赖:

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.1</version>
</dependency>

2. 引用:

使用Mybaits 分为两步:

  1. 获取 SqlSessionFactory
  2. 获取 SqlSession
  3. 获取数据、执行更新。

简单吧。

2.1 从xml中获取 SqlSessionFaction:
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

这里需要解释下 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>
  
  <environments default="development">
    <environment id="development">

      <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>
  </environments>

  
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>
  • environments :
    表示环境配置。
    在实际开发中,我们通常有多个环境,例如开发环境(development)、测试环境(test)、生产环境(production)等,不同的环境的配置都是不同的。
    因此在environments元素中,可以配置多个表示具体某个环境的environment子元素。
    而default属性用于指定默认的环境。

  • transactionManager:
    事务管理器,属性type取值有2个,JDBC|MANAGED。
    其中:JDBC表示任何对数据库的修改操作,mybatis都会自动开启事务。
    这里配置的是MANAGED,表示事务由应用程序来控制,也就是我们需要手动的开启事务和提交事务。
    和spring整合时,开启和提交事务的操作交由spring来管理。

  • datasource :
    表示数据源配置。这个更好理解,因为不同的环境中,我们访问的数据库url、username、password都是不同的,因此在每个environment元素下面都有一个dataSource配置。
    属性type表示使用的数据源类型,取值有三个:UNPOOLED|POOLED|JNDI,
    这里指定POOLED,表示使用mybatis自带的PooledDataSource。
    而dataSource内部通过property元素配置的属性,都是PooledDataSource支持的。
    注意不同的数据源实现,可以配置的property是不同的。

  • mappers :
    表示映射文件列表,前面提到通常我们针对数据库中每张表,都会建立一个映射文件。
    而在mappers元素中,就通过mapper元素,列出了所有配置文件的路径。例如mapper元素可以通过以下属性指定映射文件的路径:
    resource属性:表示映射文件位于classpath下。例如上面的配置中就表示在classpath的mappers目录下,有一个UserMapper.xml映射文件
    url属性:使用完全限定资源定位符指定映射文件路径,如file:///var/mappers/uthorMapper.xml
    class属性:通过java类来配置映射关系,可以一个java映射类对应一个xml映射文件
    package:如果有多个java映射类,且位于同一个包下面,我们可以直接使用package属性指定包名,不需要为每个java映射配置一个class属性。

如何引用第三方 Datasource :

开源社区有不少优秀的DataSource 我们可以使用, 解锁的正确方式是:

<dataSource type="com.test.mysite.common.MyselfDefineDataSourceFactory">
    <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/site-aliyun"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
</dataSource>
package com.test.mysite.common;

import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory;

import com.alibaba.druid.pool.DruidDataSource;

public class MyselfDefineDataSourceFactory extends UnpooledDataSourceFactory {
    public MyselfDefineDataSourceFactory() {
        this.dataSource = new DruidDataSource();
    }
}
2.2 在代码中构建SqlSessionFaction:
DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();        // 获取 DataSource
TransactionFactory transactionFactory = new JdbcTransactionFactory();     // jdbc transaction
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

这种方式也是简单快捷.

获取 SqlSession 的方式:

当拿到 SqlSessionFactory 之后,便可以拿到 SqlSession,每次使用完之后必须关闭:

SqlSession session = sqlSessionFactory.openSession();
try {
  Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
} finally {
  session.close();
}

每次都要 close , 代码看上去不美观,作者也很烦呀, 看到在mybatis-spring中有一个使用代理实现自动close的 SqlSession 子类SqlSessionTemplate解决了这一问题,但是在纯种mybatis中,还是没有较好的解决办法,继续烦恼中(mybatis拿到的session实体为:DefaultSqlSession)


3. 实例

在文章最后贴出作者封装的 SqlSessionFactory 构造类:

配置信息:

# 数据库连接池
datasource {
  driver : "org.h2.Driver",
  url : "jdbc:h2:mem:testDB",
  userName : "test",
  passWord : "test",
  connect-init-size : 5,
  connect-min-size : 2,
  connect-max-size : 10
}

封装类:

package com.mobvista.dataplatform.cluster.common;

import com.mobvista.dataplatform.cluster.dao.UserDefineActionMapper;
import com.mobvista.dataplatform.cluster.dao.cluster.ClusterMessageMapper;
import com.mobvista.dataplatform.cluster.dao.cluster.InstanceMessageMapper;
import com.mobvista.dataplatform.cluster.dao.cluster.InstanceStrategyMapper;
import com.mobvista.dataplatform.cluster.dao.security.SecurityMessageMapper;
import com.typesafe.config.Config;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;

import javax.sql.DataSource;

/***
 * <pre>
 *     数据库查询工具
 * </pre>
 * @user : saligia
 * @date : 2018-08-23
 */
public class QueryManager {

    private static final String DATASOURCE_DRIVER = "driver";
    private static final String DATASOURCE_URL = "url";
    private static final String DATASOURCE_USER = "userName";
    private static final String DATASOURCE_PASSWD = "passWord";

    private static final String DATASOURCE_INIT_SIZE = "connect-init-size";
    private static final String DATASOURCE_MIN_SIZE = "connect-min-size";
    private static final String DATASOURCE_MAX_SIZE = "connect-max-size";

    private static final String DEVELOPMENT = "development";

    private DataSource dataSource = null;
    private SqlSessionFactory sqlSessionFactory = null;

    private static QueryManager queryManager = null;

    private QueryManager(){
        throw new IllegalArgumentException("invalid data config error");
    }


    private QueryManager(Config dataConfig) {
        initDataSource(dataConfig);
        initSQLSessionFaction();
    }


    /**
     * <pre>
     *   初始化数据库连接池
     * </pre>
     *
     * @param dataConfig 数据库配置信息
     */
    private void initDataSource(Config dataConfig){

        BasicDataSource dataSource = new BasicDataSource();

        if (!dataConfig.hasPath(DATASOURCE_DRIVER)){
            throw new IllegalArgumentException("Init datasource error : driver invalid");
        }
        dataSource.setDriverClassName(dataConfig.getString(DATASOURCE_DRIVER));

        if(!dataConfig.hasPath(DATASOURCE_URL)){
            throw new IllegalArgumentException("Init datasource error : url invalid");
        }
        dataSource.setUrl(dataConfig.getString(DATASOURCE_URL));

        if(!dataConfig.hasPath(DATASOURCE_USER)){
            throw new IllegalArgumentException("Init datasource error : user invalid");
        }
        dataSource.setUsername(dataConfig.getString(DATASOURCE_USER));

        if(!dataConfig.hasPath(DATASOURCE_PASSWD)){
            throw new IllegalArgumentException("Init datasource error : passwd invalid");
        }
        dataSource.setPassword(dataConfig.getString(DATASOURCE_PASSWD));

        if(dataConfig.hasPath(DATASOURCE_INIT_SIZE)){
           dataSource.setInitialSize(dataConfig.getInt(DATASOURCE_INIT_SIZE));
        }

        if(dataConfig.hasPath(DATASOURCE_MIN_SIZE)){
            dataSource.setMinIdle(dataConfig.getInt(DATASOURCE_MIN_SIZE));
        }

        if(dataConfig.hasPath(DATASOURCE_MAX_SIZE)){
            dataSource.setMaxActive(dataConfig.getInt(DATASOURCE_MAX_SIZE));
        }

        this.dataSource = dataSource;
    }

    /**
     * <pre>
     *     初始化 SQLSession
     * </pre>
     *
     * @param
     */
    private void initSQLSessionFaction(){
        TransactionFactory transactionFactory = new JdbcTransactionFactory();
        Environment environment = new Environment(DEVELOPMENT, transactionFactory, dataSource);
        Configuration configuration = new Configuration(environment);
        configuration.setMapUnderscoreToCamelCase(true);

        configuration.addMapper(ClusterMessageMapper.class);
        configuration.addMapper(InstanceMessageMapper.class);
        configuration.addMapper(InstanceStrategyMapper.class);
        configuration.addMapper(SecurityMessageMapper.class);
        configuration.addMapper(UserDefineActionMapper.class);

        this.sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
    }

    /**
     * <pre>
     *     构建 QueryManager 过程
     * </pre>
     *
     * @param dataSource 数据库连接池配置信息
     */
    public static QueryManager createQueryManager(Config dataSource){
        if(queryManager == null){
            queryManager = new QueryManager(dataSource);
        }
        return  queryManager;
    }

    /**
     * <pre>
     *     获取 sql 执行session
     *     -----------------------
     *     使用结束后必须 close
     * </pre>
     *
     * @param
     */
    public SqlSession getSession(){
        return sqlSessionFactory.openSession(true);
    }


    public DataSource getDataSource(){
        return this.dataSource;
    }

}

另附 :

数据库连接池:数据库连接池原理详解与自定义连接池实现 - CSDN博客

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容