Ch9 : Play MyBatis & MariaDB

[Play MyBatis & MariaDB]
這個章節我們要學習安裝資料庫MariaDB,以及新增MyBaits資料庫工具到Play上,協助我們跟MariaDB做各種互動。
而我採用是MySQL的另外一個分支MariaDB,大多情況下,SQL語法是跟MySQL相容,而且是免費開源(Free and open source)的資料庫,也是我採用這套資料庫的原因。

那我們就開始吧!!


專案參考 : https://github.com/loveu8/playMyBtaisMariaDB/tree/Ch9


From the beginning , we are nothing. But it make everything is possible to achieve. Just do it.


[MySql]
我們會先在Windows安裝MariaDB資料庫,而我使用的是zip而不是mis安裝檔。要依序手動建立相關服務,也熟悉一下怎樣簡單建立一個資料庫服務。
(PS: 若是使用MacOSX系統,最下方有Bonus For MacOSX的安裝指引,可以參閱安裝)

Step 1 : 我們採用的版本是MariaDB 10.1.16 Stable的版本,我使用的版本是64bit的版本,請到以下網址抓取zip壓縮檔案。
網址:https://downloads.mariadb.org/

Step 2 : 當下載回來後。為了教學方便,我們直接在原本的C:/playFramework下,新增對應的目錄,並把檔案放置進來後,再解壓縮maria-10.1.16-winx64.zip檔案。
EX PATH : C:\playFramework\database

Step 3 : 下載回來之後,我們要複製一份my-medium.ini檔案,並且更名成my.ini,來去新增MySql啟動時,需要的一些設定,設定可以參考下方的設定檔。有特別寫中文註解的部份要特別注意
my.ini

[client]
#設定使用者的預設字元utf8
default-character-set=utf8
port        = 3306
socket        = /tmp/mysql.sock

# The MariaDB server
[mysqld]
port        = 3306
socket        = /tmp/mysql.sock
skip-external-locking
key_buffer_size = 16M
max_allowed_packet = 1M
table_open_cache = 64
sort_buffer_size = 512K
net_buffer_length = 8K
read_buffer_size = 256K
read_rnd_buffer_size = 512K
myisam_sort_buffer_size = 8M
# 設定MariaDB安裝路徑
basedir = C:\\playFramework\\database\\mariadb-10.1.16-winx64

# 設定MariaDB的資料庫檔所存放的位置
datadir = C:\\playFramework\\database\\mariadb-10.1.16-winx64\\data

# 設定伺服器的預設字元utf8
character-set-server = utf8
init-connect='SET NAMES utf8'
collation-server = utf8_unicode_ci

log-bin=mysql-bin

binlog_format=mixed

# required unique id between 1 and 2^32 - 1
# defaults to 1 if master-host is not set
# but will not function as a master if omitted
server-id    = 1

[mysqldump]
quick
max_allowed_packet = 16M

[mysql]
no-auto-rehash
# 設定 MySQL 用戶端的預設字元集,這裡設的是 utf8
default-character-set = utf8

[myisamchk]
key_buffer_size = 20M
sort_buffer_size = 20M
read_buffer = 2M
write_buffer = 2M

[mysqlhotcopy]
interactive-timeout


Step 4 : 因為我們採用的是no install方式,所以我們要自己安裝MySql的服務,讓作業系統知道有一個服務是MySqlDataBase。我們會再cmd模式下,下指令切換到MariaDB解壓縮的目錄,執行安裝MySql服務。

#切換目錄到安裝資料夾
cd C:\playFramework\database\mariadb-10.1.16-winx64\bin

#執行安裝指令
C:\playFramework\database\mariadb-10.1.16-winx64\bin\mysqld –install

#系統會吐出這個訊息
Service successfuly install.


Step 5 : 這時候我們已經成功安裝MySql,接下來我們要把資料庫啟動起來。
先開啟一個cmd輸入以下指令,這樣我們的MariaDB就啟動了。

cd C:\playFramework\database\mariadb-10.1.16-winx64\bin
mysqld --console


Step 6 : 設定root的帳號。再開啟一個cmd畫面來設定。我們的帳號是root,密碼是1234。要特別注意就是,因為方便介紹,root設定密碼非常簡潔,請不要在線上運作環境設定這種密碼,以免造成危險。

cd C:\playFramework\database\mariadb-10.1.16-winx64\bin
mysqladmin -u root password "1234"


Step 7 : 接下來我們使用一套免費的資料庫工具Heidisql,若有其他喜愛的工具也可以拿來使用,我們要連線到資料庫,看使用能正常運行。
下載網址 : http://www.heidisql.com/download.php?download=portable
以下是設定畫面,IP是本機127.0.0.1,預設Port 3306。帳號:root,密碼:1234

登入之後畫面。

Step 8 : 請依下圖順序,我們來創建一個Play資料庫。
這樣我們就可以成功建立一個Play的資料庫了。

Step 9 : 點選到左邊的Play資料庫後,依序執行以下基本SQL指令,看是否能順利執行。若沒有問題,我們的資料庫就算是測試建立成功了。

-- 1.建立表單
CREATE TABLE firstTable( seq int ,Message varchar(255));

-- 2.查詢
SELECT * FROM firstTable;

-- 3.新增
INSERT firstTable VALUES ('1','Hello World');
INSERT firstTable VALUES ('2','Play World');

-- 4.新增後查詢
SELECT * FROM firstTable;

-- 5.刪除
DELETE FROM firstTable WHERE seq = '1';

-- 6.刪除後查詢
SELECT * FROM firstTable;

-- 7.更新
UPDATE firstTable SET seq = '1' WHERE seq = '2';

-- 7.更新後查詢
SELECT * FROM firstTable;

-- 8.丟棄
DROP TABLE firstTable;

執行片段。

Step 10 : 為了之後方便我們啟動MySQL,我們可以寫Windowsbat檔案,寫好之後可以直接點擊啟動或關閉資料庫。
mariadb-run.bat
下面defaults意思是,指定要使用我們寫好的my.ini設定檔來啟動資料庫。

C:\playFramework\database\mariadb-10.1.16-winx64\bin\mysqld --defaults-file=C:\playFramework\database\mariadb-10.1.16-winx64\my.ini --console

mariadb-shutdown.bat
關閉資料庫,這個需要輸入root密碼,才能去關閉。

C:\playFramework\database\mariadb-10.1.16-winx64\bin\mysqladmin -u root -p shutdown


以上我們就成功的在Windows建立MariaDB資料庫,而Windows重新啟動時會自動啟用MySQL服務,當我們執行mariadb-run.bat時會失敗,需要先運行mariadb-shutdown.bat關閉後,再重啟mariadb-run.bat即可。若不喜歡Windows每次重開機自動啟動MySQL服務的話,可以從服務裡,把MySQL調成手動開啟即可。


[MyBatis]
這個部份因為(Play + MyBatis + MariaDB)相互搭配,才能達成我們想要連結資料庫的功能。程式碼主要是參閱innoq/play24-guice-mybatis後,實作出來的。在實作過程中,必須要特別注意,是否有哪個細節錯誤導致Play無法跟MariaDB連線。以下依照順序來實作吧!

Step 0 : 我們在設定Play之前,我們先去DB建立一個UserTable。來給Play+MyBaits呼叫與查詢。

-- 1.建立表單
CREATE TABLE Users( id long , name varchar(50));

-- 2.新增兩筆資料
INSERT Users VALUES ('0001','Tom');
INSERT Users VALUES ('0002','Jerry');

-- 3. 查詢
SELECT * FROM Users;


Step 1 : 設定我們的build.sbt檔案。我們要把MyBatisMariaDB需要相關的jar與宣告,寫到build.sbt,協助我們Play可以利用MyBaits來跟MariaDB資料庫連線。完成後,輸入指令下載我們需要的jar檔與編譯專案。
指令 : activator clean update compile eclipse

name := """myFirstApp"""

version := "1.0-SNAPSHOT"

lazy val root = (project in file(".")).enablePlugins(PlayJava)

scalaVersion := "2.11.7"

libraryDependencies ++= Seq(
  javaJdbc,
  cache,
  javaWs,
  // 增加mybatis , google Inject 與 mariadb 需要的jar檔
  "org.mybatis" % "mybatis" % "3.4.1",        
  "org.mybatis" % "mybatis-guice" % "3.8",
  "com.google.inject.extensions" % "guice-multibindings" % "4.1.0",
  "org.mariadb.jdbc" % "mariadb-java-client" % "1.4.6"
)

// Compile the project before generating Eclipse files, so that .class files for views and routes are present
EclipseKeys.preTasks := Seq(compile in Compile)           

// Java project. Don't expect Scala IDE       
EclipseKeys.projectFlavor := EclipseProjectFlavor.Java    

// Use .class files instead of generated .scala files for views and routes        
EclipseKeys.createSrc := EclipseCreateSrc.ValueSet(EclipseCreateSrc.ManagedClasses, EclipseCreateSrc.ManagedResources) 

// if you want to running compile , this "fork in run" must set false
fork in run := false

// 以下這兩段必須要增加到sbt檔案,目的是要把我們mybaits的xml,編譯到classpath
// 讓myBaits知道要執行那個編譯過後的xml檔案
// Add app folder as resource directory so that mapper xml files are in the classpath
unmanagedResourceDirectories in Compile <+= baseDirectory( _ / "app" )

// but filter out java and html files that would then also be copied to the classpath
excludeFilter in Compile in unmanagedResources := "*.java" || "*.html"


Step2 : 設定我們的app/application.conf。增加以下這幾段。並把前面db{}移除掉,以免干擾到我們的設定。

# 設定我們mariaDb的連線資訊
# maria Driver 路徑的寫法
db.play.driver="org.mariadb.jdbc.Driver"
# 預設連線到之前創立好的play資料庫
db.play.url="jdbc:mariadb://localhost:3306/play"
#使用者帳號與秘碼
db.play.user="root"
db.play.password="1234"
#log是否印出sql
db.play.logSql=true


# 我們之後會寫ㄧ隻MyBatisModule,讓Play可以自動呼叫到連線程式與相依的類別
# modules.MyBatisModule 是有對應到我們程式路徑,要注意擺放位置
# We need to enable the MyBatis Module we have defined (also be sure to use `+=` not `=`)
play.modules.enabled += "modules.MyBatisModule"


step 3 : 在app/pojo目錄下新增db資料夾,在app/pojo/db,新增ㄧ隻Users類別。

package pojo.db;

public class User {
    private Long id;
    private String name;

    public User(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}


Step 4 : 在app/services目錄下新增UserService類別,之後使用到Inject方式,來去執行資料庫查尋動作。

package services;

import pojo.db.User;

import java.util.List;

public interface UserService {
    List<User> all();

    User getUserById(Long id);
}


Step 5 : 在conf目錄下,新增ㄧ個services的目錄,在conf/services新增UserService.xml檔案,裡面是寫好的查詢條件。

<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="services.UserService">
    <resultMap id="userMap" type="pojo.db.User">
        <constructor>
            <idArg column="id" javaType="Long"/>
            <arg column="name" javaType="String"/>
        </constructor>
    </resultMap>

    <select id="all" resultMap="userMap">
        SELECT * FROM Users ORDER BY id
    </select>

    <select id="getUserById" parameterType="Long" resultMap="userMap">
        SELECT * FROM Users WHERE id = #{value}
    </select>
</mapper>


Step 6 : 在app目錄下新增modules資料夾,並在app/modules新增MyBatisModule類別。當我們呼叫到有addMapperClass的類別的時候,會自動幫我們建立DB連線後,並查看Interface所呼叫的功能,會對應的XML檔案指定的SQL語法,來完成存取資料庫動作。

package modules;

import com.google.inject.name.Names;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import play.db.Database;
import services.UserService;

import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.sql.DataSource;

public class MyBatisModule extends org.mybatis.guice.MyBatisModule {

    @Override
    protected void initialize() {
        environmentId("development");
        bindConstant().annotatedWith(
                Names.named("mybatis.configuration.failFast")).
                to(true);
        bindDataSourceProviderType(PlayDataSourceProvider.class);
        bindTransactionFactoryType(JdbcTransactionFactory.class);
        // 把我們要呼叫DB的類別,增加到MapperClass
        addMapperClass(UserService.class);
    }

     // 產出一個單例模式的連線
    @Singleton
    public static class PlayDataSourceProvider implements Provider<DataSource> {

        final Database db;

        private Configuration configuration;

        @Inject
        public PlayDataSourceProvider(Configuration config) {

            this.configuration = config;

            // 取得conf檔案 資料庫設定
            String dataBaseName = "play";
            String driver        = configuration.getString("db.play.driver");
            String url            = configuration.getString("db.play.url");
            String user            = configuration.getString("db.play.user");
            String password        = configuration.getString("db.play.password");

            // 建立Database物件
            Database database = Databases.createFrom(
                    dataBaseName,
                    driver,
                    url,
                    ImmutableMap.of(
                            "user", user,
                            "password", password
                    )
            );

            this.db = database;
        }

        @Override
        public DataSource get() {
            return db.getDataSource();
        }
    }

}


Step 7 : 在controller下新增ㄧ隻DbController的類別,會去執行資料庫存取動作。

package controllers;

import javax.inject.Inject;

import play.libs.Json;
import play.mvc.Controller;
import play.mvc.Result;

import services.UserService;

public class DbController extends Controller{

    private UserService userService;

    @Inject
    public DbController(UserService userService) {
        this.userService = userService;
    }

    // 取出所有使用者
    public Result listUsers() {
        return ok(Json.toJson(userService.all()));
    }

    // 根據id,找出對應的人
    public Result showUser(Long id) {
        User user = userService.getUserById(id);
        if(user!=null){
            return ok(Json.toJson(user));
        } else {
            return ok(Json.toJson("查無資料"));
        }    
    }
}


Step 8 : 在conf/routes新增以下這兩個呼叫方式。

# http://127.0.0.1:9000/db/listUsers
GET        /db/listUsers                controllers.DbController.listUsers()

# http://127.0.0.1:9000/db/showUser?id=0001
GET        /db/showUser                controllers.DbController.showUser(id : Long)

Step 9 : 再輸入ㄧ次編譯指令activator clean update compile eclipse run。並確保我們的MariaDBPlay服務都是正常啟用狀態。


開始測試是否能順利連線到資料庫。

Request
取得所有的使用者。

GET : http://127.0.0.1:9000/db/listUsers

Consose log

[info] application - Creating Pool for datasource 'default'
[info] p.a.d.DefaultDBApi - Database [default] connected at jdbc:mysql://localhost:3306/play
[info] application - db name = default
[info] application - db url  = jdbc:mysql://localhost:3306/play
[info] application - ApplicationTimer demo: Starting application at 2016-08-28T08:26:31.030Z
[info] play.api.Play - Application started (Dev)

Response

[{"id":1,"name":"Tom"},{"id":2,"name":"Jerry"}]


Request
查詢編號1的使用者是誰

GET : http://127.0.0.1:9000/db/showUser?id=1

Response

{"id":1,"name":"Tom"}


Request
查詢不存在的編號。

GET : http://127.0.0.1:9000/db/showUser?id=3

Response

"查無資料"


以上若能順利連線成功跟可以查詢到資料,那恭喜你,我們又往前了ㄧ大步。若還是不能連線到資料庫,可能要往回看看是否有遺漏的地方。而我們需要特別注意的部份是MyBatisModule這隻程式,為了未來專案可能的Database來源不止一個,就需要用Play.db.databasecreateFrom方法,去存取application我們寫好的資料庫設定,就可以達到可以存取不同資料庫的功能了。


[Bonus For MacOSX]
以下簡單介紹使用Mac系統時,快速安裝MariaDB的建置指令步驟,若是不清楚可以參閱文章介紹。

Step 1 : 安裝Homebrew的套件管理工具。
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Step 2 : 執行brew update進行更新動作。
brew update

Step 3 : 安裝MariaDB
brew install mariadb

Step 4 : 安裝完之後啟動MySql
mysql.server start

Step 5 : 安全性安裝
mysql_secure_installation

Step 6 : 連線到MariaDB
mysql -u root -p

Step 7 : 確認版本。
select @@version;

若是關閉MySQL輸入以下指令
mysql.server stop

設定root的密碼
mysqladmin -u root password "1234"

參考文章
1.利用Homebrew方式安裝MariaDB
網址: https://mariadb.com/blog/installing-mariadb-10010-mac-os-x-homebrew

2.MySQL GUI - workbench
http://www.mysql.com/products/workbench/


[Final]

這個章節特別參閱許多前人的文章所完成,其中MariaDB安裝是參閱了Power的部落格東方藍的說明與相關bat程式所完成的。

PlayMyBatis是參考國外開發者及論壇後完成的。特別感謝martin_grotzkealexklibiszTimo Loist開發者的介紹,可以實現Play使用MyBatisMariaDB做互動。

這些文章與介紹,也幫助我解決了新舊版Play透過MyBatis連結資料庫的問題,當資料庫成功連線時,辛苦就值得了!!

下個章節開始,我們會開始實戰建立一個網站,我會設計相關的資料庫表單,來實際打照一個簡單的網站,來把我們學習成果給展現出來,因為可能內容較多,會逐步分章節,一步步完成我們的網站。

最後,休息一下下,期待下個章節吧!!


[Reference]
1.MariaDB
https://mariadb.org

2.在Windows安裝Zip (noinstall)版本的MariaDB
http://eastblueps.blogspot.tw/2015/03/windowszip-noinstallmariadb.html

3.在 Windows 下安裝 MariaDB (noinstall版本)
http://www.forpower.com/blog/2016/01/29/%E5%9C%A8-windows-%E4%B8%8B%E5%AE%89%E8%A3%9D-mariadb-noinstall%E7%89%88%E6%9C%AC/

4.play24-guice-mybatis
https://www.innoq.com/en/blog/play24-guice-mybatis/

5.innoq/play24-guice-mybatis<(GITHUB)br>
https://github.com/innoq/play24-guice-mybatis

6.setting-up-play-framework-2.3.6-with-mybatis
http://alexklibisz.github.io/setting-up-play-framework-2.3.6-with-mybatis/

7.play-2.3.6-mybatis-sample(GITHUB)
https://github.com/alexklibisz/play-2.3.6-mybatis-sample

8.about-mariadb-connector-j
https://mariadb.com/kb/en/mariadb/about-mariadb-connector-j/

9.integrating-mybatis-guice-play2
https://inoio.de/blog/2013/02/07/integrating-mybatis-guice-play2/

10.JavaTestingWithDatabases
https://www.playframework.com/documentation/2.5.x/JavaTestingWithDatabases

11.JavaJPA
https://www.playframework.com/documentation/2.5.x/JavaJPA

12.multidb
https://www.playframework.com/modules/multidb-1.2/home

13.play2java-samples/guice-mybatis-multiple-db/
https://github.com/tatsuma/play2java-samples/tree/master/guice-mybatis-multiple-db

14.Play-Databases.java
https://www.codatlas.com/github.com/playframework/playframework/master/framework/src/play-java-jdbc/src/main/java/play/db/Databases.java

15.Play Database API
https://www.playframework.com/documentation/2.5.x/api/java/play/db/Databases.html

results matching ""

    No results matching ""