1. 程式人生 > >HBase 系列(十一)—— Spring/Spring Boot + Mybatis + Phoenix 整合

HBase 系列(十一)—— Spring/Spring Boot + Mybatis + Phoenix 整合

一、前言

使用 Spring+Mybatis 操作 Phoenix 和操作其他的關係型資料庫(如 Mysql,Oracle)在配置上是基本相同的,下面會分別給出 Spring/Spring Boot 整合步驟,完整程式碼見本倉庫:

  • Spring + Mybatis + Phoenix
  • SpringBoot + Mybatis + Phoenix

二、Spring + Mybatis + Phoenix

2.1 專案結構

2.2 主要依賴

除了 Spring 相關依賴外,還需要匯入 phoenix-core 和對應的 Mybatis 依賴包

<!--mybatis 依賴包-->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.2</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.6</version>
</dependency>
<!--phoenix core-->
<dependency>
    <groupId>org.apache.phoenix</groupId>
    <artifactId>phoenix-core</artifactId>
    <version>4.14.0-cdh5.14.2</version>
</dependency>

2.3 資料庫配置檔案

在資料庫配置檔案 jdbc.properties 中配置資料庫驅動和 zookeeper 地址

# 資料庫驅動
phoenix.driverClassName=org.apache.phoenix.jdbc.PhoenixDriver
# zookeeper地址
phoenix.url=jdbc:phoenix:192.168.0.105:2181

2.4 配置資料來源和會話工廠

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- 開啟註解包掃描-->
    <context:component-scan base-package="com.heibaiying.*"/>

    <!--指定配置檔案的位置-->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <!--配置資料來源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <!--Phoenix 配置-->
        <property name="driverClassName" value="${phoenix.driverClassName}"/>
        <property name="url" value="${phoenix.url}"/>
    </bean>

    <!--配置 mybatis 會話工廠 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!--指定 mapper 檔案所在的位置-->
        <property name="mapperLocations" value="classpath*:/mappers/**/*.xml"/>
        <property name="configLocation" value="classpath:mybatisConfig.xml"/>
    </bean>

    <!--掃描註冊介面 -->
    <!--作用:從介面的基礎包開始遞迴搜尋,並將它們註冊為 MapperFactoryBean(只有至少一種方法的接口才會被註冊;, 具體類將被忽略)-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--指定會話工廠 -->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <!-- 指定 mybatis 介面所在的包 -->
        <property name="basePackage" value="com.heibaiying.dao"/>
    </bean>

</beans>

2.5 Mybtais引數配置

新建 mybtais 配置檔案,按照需求配置額外引數, 更多 settings 配置項可以參考官方文件

<?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">

<!-- mybatis 配置檔案 -->
<configuration>
    <settings>
        <!-- 開啟駝峰命名 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!-- 列印查詢 sql -->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
</configuration>

2.6 查詢介面

public interface PopulationDao {

    List<USPopulation> queryAll();

    void save(USPopulation USPopulation);

    USPopulation queryByStateAndCity(@Param("state") String state, @Param("city") String city);

    void deleteByStateAndCity(@Param("state") String state, @Param("city") String city);
}
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.heibaiying.dao.PopulationDao">


    <select id="queryAll" resultType="com.heibaiying.bean.USPopulation">
        SELECT * FROM us_population
    </select>

    <insert id="save">
        UPSERT INTO us_population VALUES( #{state}, #{city}, #{population} )
    </insert>

    <select id="queryByStateAndCity" resultType="com.heibaiying.bean.USPopulation">
        SELECT * FROM us_population WHERE state=#{state} AND city = #{city}
    </select>

    <delete id="deleteByStateAndCity">
        DELETE FROM us_population WHERE state=#{state} AND city = #{city}
    </delete>

</mapper>

2.7 單元測試

@RunWith(SpringRunner.class)
@ContextConfiguration({"classpath:springApplication.xml"})
public class PopulationDaoTest {

    @Autowired
    private PopulationDao populationDao;

    @Test
    public void queryAll() {
        List<USPopulation> USPopulationList = populationDao.queryAll();
        if (USPopulationList != null) {
            for (USPopulation USPopulation : USPopulationList) {
                System.out.println(USPopulation.getCity() + " " + USPopulation.getPopulation());
            }
        }
    }

    @Test
    public void save() {
        populationDao.save(new USPopulation("TX", "Dallas", 66666));
        USPopulation usPopulation = populationDao.queryByStateAndCity("TX", "Dallas");
        System.out.println(usPopulation);
    }

    @Test
    public void update() {
        populationDao.save(new USPopulation("TX", "Dallas", 99999));
        USPopulation usPopulation = populationDao.queryByStateAndCity("TX", "Dallas");
        System.out.println(usPopulation);
    }


    @Test
    public void delete() {
        populationDao.deleteByStateAndCity("TX", "Dallas");
        USPopulation usPopulation = populationDao.queryByStateAndCity("TX", "Dallas");
        System.out.println(usPopulation);
    }
}

三、SpringBoot + Mybatis + Phoenix

3.1 專案結構

3.2 主要依賴

<!--spring 1.5 x 以上版本對應 mybatis 1.3.x (1.3.1)
        關於更多 spring-boot 與 mybatis 的版本對應可以參見 <a href="http://www.mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/">-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency>
<!--phoenix core-->
<dependency>
    <groupId>org.apache.phoenix</groupId>
    <artifactId>phoenix-core</artifactId>
    <version>4.14.0-cdh5.14.2</version>
</dependency>
<dependency>

spring boot 與 mybatis 版本的對應關係:

MyBatis-Spring-Boot-Starter 版本 MyBatis-Spring 版本 Spring Boot 版本
1.3.x (1.3.1) 1.3 or higher 1.5 or higher
1.2.x (1.2.1) 1.3 or higher 1.4 or higher
1.1.x (1.1.1) 1.3 or higher 1.3 or higher
1.0.x (1.0.2) 1.2 or higher 1.3 or higher

3.3 配置資料來源

在 application.yml 中配置資料來源,spring boot 2.x 版本預設採用 Hikari 作為資料庫連線池,Hikari 是目前 java 平臺效能最好的連線池,效能好於 druid。

spring:
  datasource:
    #zookeeper 地址
    url: jdbc:phoenix:192.168.0.105:2181
    driver-class-name: org.apache.phoenix.jdbc.PhoenixDriver

    # 如果不想配置對資料庫連線池做特殊配置的話,以下關於連線池的配置就不是必須的
    # spring-boot 2.X 預設採用高效能的 Hikari 作為連線池 更多配置可以參考 https://github.com/brettwooldridge/HikariCP#configuration-knobs-baby
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      # 池中維護的最小空閒連線數
      minimum-idle: 10
      # 池中最大連線數,包括閒置和使用中的連線
      maximum-pool-size: 20
      # 此屬性控制從池返回的連線的預設自動提交行為。預設為 true
      auto-commit: true
      # 允許最長空閒時間
      idle-timeout: 30000
      # 此屬性表示連線池的使用者定義名稱,主要顯示在日誌記錄和 JMX 管理控制檯中,以標識池和池配置。 預設值:自動生成
      pool-name: custom-hikari
      #此屬性控制池中連線的最長生命週期,值 0 表示無限生命週期,預設 1800000 即 30 分鐘
      max-lifetime: 1800000
      # 資料庫連線超時時間,預設 30 秒,即 30000
      connection-timeout: 30000
      # 連線測試 sql 這個地方需要根據資料庫方言差異而配置 例如 oracle 就應該寫成  select 1 from dual
      connection-test-query: SELECT 1

# mybatis 相關配置
mybatis:
  configuration:
    # 是否列印 sql 語句 除錯的時候可以開啟
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3.4 新建查詢介面

上面 Spring+Mybatis 我們使用了 XML 的方式來寫 SQL,為了體現 Mybatis 支援多種方式,這裡使用註解的方式來寫 SQL。

@Mapper
public interface PopulationDao {

    @Select("SELECT * from us_population")
    List<USPopulation> queryAll();

    @Insert("UPSERT INTO us_population VALUES( #{state}, #{city}, #{population} )")
    void save(USPopulation USPopulation);

    @Select("SELECT * FROM us_population WHERE state=#{state} AND city = #{city}")
    USPopulation queryByStateAndCity(String state, String city);


    @Delete("DELETE FROM us_population WHERE state=#{state} AND city = #{city}")
    void deleteByStateAndCity(String state, String city);
}

3.5 單元測試

@RunWith(SpringRunner.class)
@SpringBootTest
public class PopulationTest {

    @Autowired
    private PopulationDao populationDao;

    @Test
    public void queryAll() {
        List<USPopulation> USPopulationList = populationDao.queryAll();
        if (USPopulationList != null) {
            for (USPopulation USPopulation : USPopulationList) {
                System.out.println(USPopulation.getCity() + " " + USPopulation.getPopulation());
            }
        }
    }

    @Test
    public void save() {
        populationDao.save(new USPopulation("TX", "Dallas", 66666));
        USPopulation usPopulation = populationDao.queryByStateAndCity("TX", "Dallas");
        System.out.println(usPopulation);
    }

    @Test
    public void update() {
        populationDao.save(new USPopulation("TX", "Dallas", 99999));
        USPopulation usPopulation = populationDao.queryByStateAndCity("TX", "Dallas");
        System.out.println(usPopulation);
    }


    @Test
    public void delete() {
        populationDao.deleteByStateAndCity("TX", "Dallas");
        USPopulation usPopulation = populationDao.queryByStateAndCity("TX", "Dallas");
        System.out.println(usPopulation);
    }

}

附:建表語句

上面單元測試涉及到的測試表的建表語句如下:

CREATE TABLE IF NOT EXISTS us_population (
      state CHAR(2) NOT NULL,
      city VARCHAR NOT NULL,
      population BIGINT
      CONSTRAINT my_pk PRIMARY KEY (state, city));
      
-- 測試資料
UPSERT INTO us_population VALUES('NY','New York',8143197);
UPSERT INTO us_population VALUES('CA','Los Angeles',3844829);
UPSERT INTO us_population VALUES('IL','Chicago',2842518);
UPSERT INTO us_population VALUES('TX','Houston',2016582);
UPSERT INTO us_population VALUES('PA','Philadelphia',1463281);
UPSERT INTO us_population VALUES('AZ','Phoenix',1461575);
UPSERT INTO us_population VALUES('TX','San Antonio',1256509);
UPSERT INTO us_population VALUES('CA','San Diego',1255540);
UPSERT INTO us_population VALUES('CA','San Jose',912332);

更多大資料系列文章可以參見 GitHub 開源專案: 大資料入門指南