- 投稿日:2020-09-19T17:15:08+09:00
Lambda上でmysqlclientを動かす
概要
LambdaにてPythonを使用時、MySQLクライアントとして
mysqlclient
を使うもの(SQLAlchemy等)を利用する場合、いろいろ準備が必要。
mysqlclient
は1.4.6
を使う- AmazonLinux2から
libmysqlclient.so.18
を拾ってくるlibmysqlclient.so.18
をLambdaへ上げた際に、Lambda上でライブラリ用パスへ配置する
mysqlclient
は1.4.6
を使うpip install mysqlclient===1.4.6細かい原理は不明だが
2.0.1
を使おうとすると、'_mysql'がないと怒られる。。
libmysqlclient.so.18
を拾ってくるAmazonLinux2用の
libmysqlclient.so.18
が必要になるのでビルドする。コンテナ起動
docker run -it amazonlinux:2 bashコンテナ内
libmysqlclient.so.18
を入れる。yum update -y yum install -y gcc mysql-devel mysql-libs # /lib64/mysql/libmysqlclient.so.18 が入るローカルPC
docker cp
等でlibmysqlclient.so.18
をローカルへコピーする。docker cp container:/lib64/mysql/libmysqlclient.so.18.0.0 local_path
libmysqlclient.so.18
をLambdaに配置する際の注意Lambdaのコンテナ上のライブラリのパスが、↓になっているので、
LD_LIBRARY_PATH=/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib
libmysqlclient.so.18
がLambdaコンテナに配置された際に上記のパスに配置されるようにする必要がある。例:レイヤーとしてアップした場合
レイヤーのファイルは
/opt
内に展開されるが、/opt/lib
の位置に.so
が来る必要がある。※
venv/lib/site-packages
内をレイヤーとして上げる場合、venv/lib/site-packages/lib
に.so
を入れる。例:Lambda用のソースに紛れ込ませる場合
/var/task
に展開されるので、lib
を作って、その中に.so
を入れる。
- 投稿日:2020-09-19T16:31:37+09:00
Go(Echo)×MySQL×Docker×Clean ArchitectureでAPIサーバー構築してみた
はじめに
タイトルにもある通り、Go×MySQL×DockerでAPIサーバーを作ってみました。
はじめは、・Goで簡単なREST APIを作ってみる
・Dockerで開発環境を立てるを目的として作っていたのですが、ディレクトリ構成をどうしようか悩んでいろいろ調べているとGo×クリーンアーキテクチャでAPIサーバーを作っている記事をたくさん発見したので、クリーンアーキテクチャやってみよう、ということでやってみました。
ということでこの記事は、
・GoでAPIを書いてみたい
・Dockerで開発環境をたてたい
・その際にクリーンアーキテクチャを採用してみたいぐらいの温度感の方におすすめです。
逆に、がっつりクリーンアーキテクチャを勉強したいという方にはあまり参考にならないかもしれません。。
なお、
フレームワークにEcho (https://echo.labstack.com/)
DBへのアクセスにはGorm (https://github.com/go-gorm/gorm)
を使用しています。準備編
開発環境
Dockerで開発環境を構築しました。
Dockerfile
基本的なDockerfileの書き方は Dockerfile 公式リファレンス が参考になります。
では、さらっとですが順番に見ていきます。
まずはGoです。
docker/api/DockerfileFROM golang:1.14 # go moduleを使用 ENV GO111MODULE=on # アプリケーションを実行するディレクトリを指定 WORKDIR /go/src/github.com/Le0tk0k/go-rest-api # 上記のディレクトリにgo.modとgo.sumをコピー COPY go.mod go.sum ./ # 上記のファイルに変更がなければキャッシュ利用できる RUN go mod download COPY . . RUN go build . RUN go get github.com/pilu/fresh EXPOSE 8080 # freshコマンドでサーバーを起動 CMD ["fresh"]github.com/pilu/fresh でホットリロードできるようにしました。
他は特に変わったところはありません。参考
・Using go mod download to speed up Golang Docker builds
・Go v1.11 + Docker + fresh でホットリロード開発環境を作って愉快なGo言語生活次にMySQLです。
docker/mysql/DockerfileFROM mysql EXPOSE 3306 # MySQL設定ファイルをイメージ内にコピー COPY ./docker/mysql/my.cnf /etc/mysql/conf.d/my.cnf CMD ["mysqld"]MySQLの設定ファイルは以下のようになりました。
MySQL8.0以降では接続時の認証方式が変更になっているため、2行目の記述が必要になるらしい。
あと、文字化けを防ぐために文字コードを変更しています。docker/mysql/my.cnf[mysqld] default_authentication_plugin=mysql_native_password character-set-server=utf8mb4 [client] default-character-set=utf8mb4/docker-entrypoint-initdb.d/ というディレクトリ内に初期化用のSQLやスクリプトを置いておくと、最初にimageを起動したときにデータの初期化を自動的に行えます。
ということで、テーブルを作成します。
docker/mysql/db/init.sqlCREATE DATABASE IF NOT EXISTS go_rest_api; USE go_rest_api; CREATE TABLE IF NOT EXISTS users ( id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, name VARCHAR(256) NOT NULL, age INT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, updated_at TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8;docker-compose.yml
こちらも Compose ファイル・公式リファレンス が参考になります。
docker-compose.ymlversion: '3' services: db: build: # Dockerfileのあるディレクトリのパスを指定 context: . dockerfile: ./docker/mysql/Dockerfile ports: # 公開ポートを指定 - "3306:3306" volumes: # 起動時にデータの初期化を行う - ./docker/mysql/db:/docker-entrypoint-initdb.d # mysqlの永続化 - ./docker/mysql/db/mysql_data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: go_rest_api MYSQL_USER: user MYSQL_PASSWORD: password api: build: context: . dockerfile: ./docker/api/Dockerfile volumes: - ./:/go/src/github.com/Le0tk0k/go-rest-api ports: - "8080:8080" depends_on: # dbが先に起動する - dbmysqlの永続化をしているので、コンテナを立ち上げ直した場合も、以前のデータが残ったままになります。
また、apiにdepend_onを指定することで、先にdbが起動し、その次にapiが起動するようになります。
しかし、depend_onは起動する順番を指定するだけで、出来上がるまでは待ってくれないので、別で対策が必要です。
なお、対策については実装編で紹介しています。参考
クリーンアーキテクチャ
クリーンアーキテクチャは、The Clean Architecture で提唱されているアーキテクチャです。
僕はそもそも、アーキテクチャ?何それ?状態だったのですが、以下の記事を読んで
上澄み1mmぐらいは理解できた気がします。他にもたくさん記事があるのでぜひ調べてみてください!参考 (クリーンアーキテクチャ以外の記事もあります)
- クリーンアーキテクチャの書籍を読んだのでAPIサーバを実装してみた
- 今すぐ「レイヤードアーキテクチャ+DDD」を理解しよう。(golang)
- Clean ArchitectureでAPI Serverを構築してみる
- 【Golang + レイヤードアーキテクチャー】DDD を意識して Web API を実装してみる
実装編
ディレクトリ構成
ディレクトリ構成は以下の通りです。
├── docker │ ├── api │ │ └── Dockerfile │ └── mysql │ ├── Dockerfile │ ├── db │ │ ├── init.sql │ │ └── mysql_data │ └── my.cnf ├── docker-compose.yml ├── domain │ └── user.go ├── infrastructure │ ├── router.go │ └── sqlhandler.go ├── interfaces │ ├── controllers │ │ ├── context.go │ │ ├── error.go │ │ └── user_controller.go │ └── database │ ├── sql_handler.go │ └── user_repository.go |── usecase │ ├── user_interactor.go │ └── user_repository.go ├── server.go ├── go.mod ├── go.sumdomain → Entities層
infrastructure → Frameworks & Drivers層
interfaces → Interface層
usecase → Use cases層に対応しています。
Domain ( Entities層 )
最も内側にある層で、どこにも依存しない層となります。
Userモデルを定義していきます。なお、
json:"-"
については、- と書くと出力されなくなります。domain/user.gopackage domain import "time" type User struct { ID int `gorm:"primary_key" json:"id"` Name string `json:"name"` Age int `json:"age"` CreatedAt time.Time `json:"-"` UpdatedAt time.Time `json:"-"` } type Users []UserInterfaces/database, Infrastructure (Interface層, Frameworks & Driver層)
次に、データベース周辺を実装していきます。
データベースの接続は外部との接続となるので、一番外側のInfrastructure層に定義します。infrastructure/sqlhandler.gopackage infrastructure import ( "fmt" "time" "github.com/Le0tk0k/go-rest-api/interfaces/database" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" ) type SqlHandler struct { Conn *gorm.DB } func NewMySqlDb() database.SqlHandler { connectionString := fmt.Sprintf( "%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=true&loc=Local", "user", "password", "db", "3306", "go_rest_api", ) conn, err := open(connectionString, 30) if err != nil { panic(err) } //接続できているか確認 err = conn.DB().Ping() if err != nil { panic(err) } // ログの詳細を出力 conn.LogMode(true) // DBのエンジンを設定 conn.Set("gorm:table_options", "ENGINE=InnoDB") sqlHandler := new(SqlHandler) sqlHandler.Conn = conn return sqlHandler } // MySQLの立ち上がりを確認してからapiコンテナが立ち上がるようにする func open(path string, count uint) (*gorm.DB, error) { db, err := gorm.Open("mysql", path) if err != nil { if count == 0 { return nil, fmt.Errorf("Retry count over") } time.Sleep(time.Second) count-- return open(path, count) } return db, nil } func (handler *SqlHandler) Find(out interface{}, where ...interface{}) *gorm.DB { return handler.Conn.Find(out, where...) } func (handler *SqlHandler) Create(value interface{}) *gorm.DB { return handler.Conn.Create(value) } func (handler *SqlHandler) Save(value interface{}) *gorm.DB { return handler.Conn.Save(value) } func (handler *SqlHandler) Delete(value interface{}) *gorm.DB { return handler.Conn.Delete(value) }opan()では、dbコンテナが立ち上がるまで待ってからapiコンテナが立ち上がるように設定しています。
今回は、Goのコードでこの機能を実装しましたが、シェルスクリプトで実装する方がいいのでしょうか?ベストプラクティスがわかりません、、
参考
- docker-compose upでMySQLが起動するまで待つ方法(2種類紹介)なお、infrastructure層はdb接続のみにして、実際の処理はinterfaces/database層に実装します。
interfaces/database/user_repository.gopackage database import ( "github.com/Le0tk0k/go-rest-api/domain" ) type UserRepository struct { SqlHandler } func (userRepository *UserRepository) FindByID(id int) (user domain.User, err error) { if err = userRepository.Find(&user, id).Error; err != nil { return } return } func (userRepository *UserRepository) Store(u domain.User) (user domain.User, err error) { if err = userRepository.Create(&u).Error; err != nil { return } user = u return } func (userRepository *UserRepository) Update(u domain.User) (user domain.User, err error) { if err = userRepository.Save(&u).Error; err != nil { return } user = u return } func (userRepository *UserRepository) DeleteByID(user domain.User) (err error) { if err = userRepository.Delete(&user).Error; err != nil { return } return } func (userRepository *UserRepository) FindAll() (users domain.Users, err error) { if err = userRepository.Find(&users).Error; err != nil { return } return }UserRepositoryにSqlHandlerを埋め込んでいます。
domain層をインポートしていますが、これは最も内側にある層なので、依存関係は守れています。しかし、SqlHandlerは1番外側のInfrastructure層に定義したので、依存関係が内から外に向いており、ルールを守れていないのでは?という疑問が生まれますが、実はここで呼んでいるSqlHandlerはInfrastructure層に定義した構造体ではなく、同階層であるinterface/database層に定義したインターフェースなのです。
これをDIP(依存関係逆転の原則)といいます。どういうことかといいますと、interfaces/database/user_repository.goでは、Infrastructure層で定義されている処理を呼んでしまうと依存関係が内→外になってしまい依存関係を守れていないことになります。それを避けるために同階層にDBとのやりとりをinterfaceで定義しておき、それを呼び出しましょうということです。
これで、実際にはInfrastructure層で処理を行っているが、interfaces/database/user_repository.goではSqlHandlerインターフェースを呼び出しているので依存関係は守れていることになります。そしてGoでは、型TがインターフェースIで定義されているメソッドを全て持つとき、インターフェースIを実装していることになるので、Infrastructure.SqlHandler構造体にinterfaces/databases/sql_handerのSqlHandlerインターフェースで定義されているメソッドを定義しています。
interfaces/database/sql_handler.gopackage database import "github.com/jinzhu/gorm" type SqlHandler interface { Find(interface{}, ...interface{}) *gorm.DB Create(interface{}) *gorm.DB Save(interface{}) *gorm.DB Delete(interface{}) *gorm.DB }Usecase ( Use Case層 )
Usecase層では、interfaces/database層から情報を受け取り、interfaces/controller層へと情報を渡す役割を持ちます。
usecase/user_interactor.gopackage usecase import "github.com/Le0tk0k/go-rest-api/domain" type UserInteractor struct { UserRepository UserRepository } func (interactor *UserInteractor) UserById(id int) (user domain.User, err error) { user, err = interactor.UserRepository.FindByID(id) return } func (interactor *UserInteractor) Users() (users domain.Users, err error) { users, err = interactor.UserRepository.FindAll() return } func (interactor *UserInteractor) Add(u domain.User) (user domain.User, err error) { user, err = interactor.UserRepository.Store(u) return } func (interactor *UserInteractor) Update(u domain.User) (user domain.User, err error) { user, err = interactor.UserRepository.Update(u) return } func (interactor *UserInteractor) DeleteById(user domain.User) (err error) { err = interactor.UserRepository.DeleteByID(user) return }UserInteractorはUserRepositoryを呼び出していますが、これもInterfase層から呼び出してしまうと内→外への依存となり依存関係を守れなくなってしまうので、同階層にuser_repository.goを作成し、インターフェースを実装してDIP(依存関係逆転の原則)を利用して依存関係を守ります。
usecase/user_repository.gopackage usecase import "github.com/Le0tk0k/go-rest-api/domain" type UserRepository interface { FindByID(id int) (domain.User, error) Store(domain.User) (domain.User, error) Update(domain.User) (domain.User, error) DeleteByID(domain.User) error FindAll() (domain.Users, error) }Interfaces/controllers, Infrastructure (Interface層, Frameworks & Driver層)
そして、コントローラーとルーターを実装していきます。
interfaces/controllers/user_controller.gopackage controllers import ( "strconv" "github.com/Le0tk0k/go-rest-api/domain" "github.com/Le0tk0k/go-rest-api/interfaces/database" "github.com/Le0tk0k/go-rest-api/usecase" ) type UserController struct { Interactor usecase.UserInteractor } func NewUserController(sqlHandler database.SqlHandler) *UserController { return &UserController{ Interactor: usecase.UserInteractor{ UserRepository: &database.UserRepository{ SqlHandler: sqlHandler, }, }, } } func (controller *UserController) CreateUser(c Context) (err error) { u := domain.User{} c.Bind(&u) user, err := controller.Interactor.Add(u) if err != nil { c.JSON(500, NewError(err)) return } c.JSON(201, user) return } func (controller *UserController) GetUsers(c Context) (err error) { users, err := controller.Interactor.Users() if err != nil { c.JSON(500, NewError(err)) return } c.JSON(200, users) return } func (controller *UserController) GetUser(c Context) (err error) { id, _ := strconv.Atoi(c.Param("id")) user, err := controller.Interactor.UserById(id) if err != nil { c.JSON(500, NewError(err)) return } c.JSON(200, user) return } func (controller *UserController) UpdateUser(c Context) (err error) { id, _ := strconv.Atoi(c.Param("id")) u := domain.User{ID: id} c.Bind(&u) user, err := controller.Interactor.Update(u) if err != nil { c.JSON(500, NewError(err)) return } c.JSON(201, user) return } func (controller *UserController) DeleteUser(c Context) (err error) { id, _ := strconv.Atoi(c.Param("id")) user := domain.User{ID: id} err = controller.Interactor.DeleteById(user) if err != nil { c.JSON(500, NewError(err)) return } c.JSON(200, user) return }echoはecho.Contextを使用するので、今回利用するメソッドのインターフェイスを定義します。
interfaces/controllers/context.gopackage controllers type Context interface { Param(string) string Bind(interface{}) error JSON(int, interface{}) error }interfaces/controllers/error.gopackage controllers type Error struct { Message string } func NewError(err error) *Error { return &Error{ Message: err.Error(), } }ルーティングはechoを使用している (外部パッケージを使用している)ので、Infrastructure層に実装します。
なお、uesrController.関数(c)で引数にecho.Context型を渡せているのは、echo.Contextがinterfaces/controllers/context.goのcontextインターフェースを満たしているからです。
(つまり、echo.Context型はcontextインターフェースのメソッドをすべて持っている。)infrastructure/router.gopackage infrastructure import ( "github.com/Le0tk0k/go-rest-api/interfaces/controllers" "github.com/labstack/echo" "github.com/labstack/echo/middleware" ) func Init() { e := echo.New() userController := controllers.NewUserController(NewMySqlDb()) // アクセスログのようなリクエスト単位のログを出力する e.Use(middleware.Logger()) // アプリケーションのどこかで予期せずにpanicを起こしてしまっても、サーバは落とさずにエラーレスポンスを返せるようにリカバリーする e.Use(middleware.Recover()) e.GET("/users", func(c echo.Context) error { return userController.GetUsers(c) }) e.GET("/users/:id", func(c echo.Context) error { return userController.GetUser(c) }) e.POST("/users", func(c echo.Context) error { return userController.CreateUser(c) }) e.PUT("/users/:id", func(c echo.Context) error { return userController.UpdateUser(c) }) e.DELETE("/users/:id", func(c echo.Context) error { return userController.DeleteUser(c) }) e.Logger.Fatal(e.Start(":8080")) }最後に、server.goから呼び出します。
server.gopackage main import "github.com/Le0tk0k/go-rest-api/infrastructure" func main() { infrastructure.Init() }実行編
では、完成したAPIを叩いてみましょう。
今回はPostmanを使用してみたいと思います。 (https://www.postman.com/downloads/)まずHeadersのContent-Typeをapplication/jsonにします。
GetUsers
全ユーザーを取得してみます。
/usersにGETリクエストを送ります。
Getuser
任意のユーザーを取得してみます。
/users/:idにGETリクエストを送ります。
CreateUser
まずはUserを作成してみます。
/usersにPOSTリクエストを送ります。
UpdateUser
任意のユーザーを更新してみます。
/users/:idにPUTリクエストを送ります。
DeleteUser
任意のユーザーを削除してみます。
/users/:idにDELETEリクエストを送ります。
しっかり機能してます!
さいごに
Dockerで開発環境を立ててREST APIを作るだけだったはずが、クリーンアーキテクチャまで勉強することになり大変でしたが、アーキテクチャを知るとても良い機会になったと思います。
今回ぐらいの小さいAPIだと逆に複雑になった感はありますが、大規模だったら良さが発揮されるのかなといった感想を持ちました。
(実際のところ、あまり理解できていないので)また設計についても勉強していきたいと思います!
- 投稿日:2020-09-19T13:30:39+09:00
Local by FlywheelのMySQLにゲスト側ではなくホスト側からWP-CLIなどで接続する
Local by Flywheelなどの仮想環境のDBへホスト側のWP-CLIからアクセスしようとしてもうまくいきません。
$ wp post list Error: Error establishing a database connection.これは
wp-config.php
に記載されているDB接続情報が仮想環境間での接続情報となっているからです。Local by Flywheelに記載されているDBの接続情報のうち、Socketを調べます。
この文字列をコピーし、
wp-config.php
に下記のようにlocalhost:
に続けて記載します。app/public/wp-config.php/** MySQL hostname */ define( 'DB_HOST', 'localhost:/Users/yousan/Library/Application Support/Local/run/_BXXXXXXX/mysql/mysqld.sock' );これでつながるようになります。便利!
$ wp post list +----+--------------+-------------+---------------------+-------------+ | ID | post_title | post_name | post_date | post_status | +----+--------------+-------------+---------------------+-------------+ | 1 | Hello world! | hello-world | 2020-09-19 01:32:34 | publish | +----+--------------+-------------+---------------------+-------------+
- 投稿日:2020-09-19T13:17:16+09:00
Go(Gin)+MySQLなDocker環境でpanic: dial tcp 127.0.0.1:3306: connect: connection refusedに苛まれた
症状
タイトルの通り。
解決策
こちらに見事なまでにおんなじ症状の方がいて、言われるがままにMySQLの接続情報を修正したところ無事直りました。以下Before/Afterです。
Before
docker-compose.ymlversion: "3" services: app: build: . depends_on: - db volumes: - ./:/go/src/app ports: - 3000:3000 environment: MYSQL_DATABASE: go_app_dev MYSQL_USER: docker MYSQL_PASSWORD: password db: image: mysql:5.7 container_name: dockerMySQL volumes: - ./storage/mysql_data:/var/lib/mysql ports: - 3306:3306 environment: MYSQL_DATABASE: go_app_dev MYSQL_USER: docker MYSQL_PASSWORD: password MYSQL_ROOT_PASSWORD: passworddb/db.gopackage db import ( "fmt" "os" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" ) var ( db *gorm.DB err error ) func Init() { user = os.Getenv("MySQL_USER") pass = os.Getenv("MYSQL_PASSWORD") dbname := os.Getenv("MYSQL_DATABASE") connection := fmt.Sprintf("%s:%s@/%s?charset=utf8&parseTime=True&loc=Local", user, pass, dbname) db, err := gorm.Open("mysql", connection) if err != nil { panic(err) } }After
docker-compose.ymlversion: "3" services: app: build: . depends_on: - db volumes: - ./:/go/src/app ports: - 3000:3000 environment: MYSQL_DATABASE: go_app_dev MYSQL_HOST: dockerMySQL # 追加!! MYSQL_USER: docker MYSQL_PASSWORD: password db: image: mysql:5.7 container_name: dockerMySQL # 追加!! volumes: - ./storage/mysql_data:/var/lib/mysql ports: - 3306:3306 environment: MYSQL_DATABASE: go_app_dev MYSQL_USER: docker MYSQL_PASSWORD: password MYSQL_ROOT_PASSWORD: passworddb/db.go// ...略 func Init() { user = os.Getenv("MySQL_USER") pass = os.Getenv("MYSQL_PASSWORD") host = os.Getenv("MYSQL_HOST") // ココ!! dbname := os.Getenv("MYSQL_DATABASE") connection := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8&parseTime=True&loc=Local", user, pass, host, dbname) // 修正!! db, err := gorm.Open("mysql", connection) if err != nil { panic(err) } }決め手はgorm.Openの第二引数で接続情報を指定する際に、MySQLを動かしているDockerコンテナのコンテナ名で接続するという点でした。そもそもBeforeのコードでMySQLに接続できなかったのはMySQLがlocalhost,あるいはTCPの3306番ポートでListenしていなかったからです。そしてdocker-composeで起動しているコンテナ達はdocker networkを介して通信しているため、ネットワーク名の代わりにコンテナ名で接続することが可能であり、Afterに載せたような接続情報でappコンテナからdbコンテナに接続できるということらしいです。このような理解で合っているかは少々自信がありませんがw
参考
- 投稿日:2020-09-19T13:17:05+09:00
MySQLのデータベース操作
ターミナルでSQLを実行し、データベースの操作を行う際の備忘メモ。
ログイン
command% mysql -u root「-u root」というオプションで、MySQLであらかじめ用意されているユーザーでログインする。
データベースの作成
commandmysql> CREATE DATABASE データベース名;「CREATE」は、データベースやテーブルを作成できるSQLの文。
データベースの一覧表示
commandmysql> SHOW DATABASES;「SHOW」は、データベースやテーブルを一覧表示できるSQLの文。
データベースの削除
commandmysql> DROP DATABASE データベース名;「DROP」は、データベースやテーブルを削除できるSQLの文。
テーブルの構造確認
commandmysql> SHOW columns FROM テーブル名;「FROM」は、対象となるテーブルを指定する際に使用するSQLの句。
カラムの追加
commandmysql> ALTER TABLE テーブル名 ADD (カラム名 カラムの型, ……);「ALTER」は、データベースやテーブルを編集できるSQLの文。
カラムの変更
commandmysql> ALTER TABLE テーブル名 CHANGE 古いカラム名 新しいカラム名 新しいカラムの型;カラムの削除
commandmysql> ALTER TABLE テーブル名 DROP カラム名;
- 投稿日:2020-09-19T12:07:18+09:00
[laravel]Mysqlとの接続メモ
前提条件
Mysqlはインストール済、dbをcreate済、環境はMacOS
設定
config/database.php
return [ 'default' => env('DB_CONNECTION', 'mysql'), 'connections' => [ 'mysql' => [ 'driver' => 'mysql', 'url' => env('DATABASE_URL'), 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), 'database' => env('DB_DATABASE', '※接続するデータベース名'), 'username' => env('DB_USERNAME', '※ユーザ名'), 'password' => env('DB_PASSWORD', '※パスワード'), ], ].env
DB_USERNAME=※ユーザ名 DB_PASSWORD=※パスワード接続確認
$ php artisan serve正しく接続してなければエラーが返ってくる。
所感
.envはdatabase.phpを上書きするようだ。本番環境に置く時に.envでパラメータ上書きして使うのかな?
- 投稿日:2020-09-19T11:43:18+09:00
C#でMySQLを使う - 1.Visual Studio 2019+MySQL 5.7 Connectorsインストール編
前提と準備
C#の記事
- C#でMySQLを使う - 1.開発環境インストール【この記事】
- C#でMySQLを使う - 2.SELECT・画面表示
最近私がプライベートで、三浦半島の一眼レフ写真や小さなアトラクションを通し、多くの方が自然と歴史などを通して感じていかれるWebサイトを制作しておりまして、ロリポップ!レンタルサーバーにPHP+MySQLを使用しています(*´꒳`*)
そのMySQLのデータ登録ですが、インターネットでPHPからMySQLを登録できるとなると、PHP側で登録用のアカウントを作らなければならなかったり、ログインなどのセキュリティを強固にする必要があっても、やはりインターネット上である以上は限度があるため、ローカルでMySQLにデータ登録し、その生成したSQLパッチを運用中のサーバーに適用しています。そうなるとインターネット上に管理画面を作る必要がなく、多少はマシになるものの、ローカルでMySQLデータ登録のプログラムを作成しなければなりません。
そこで、私の場合は、WindowsプログラムをC#で制作し、そこからMySQLに接続し、SQLパッチをテキストとして生成するというやり方を採っています。その際にどうしても必要なのは、C#(.NET)からMySQLに接続できるための外部ライブラリを使い、Visual Studioには標準で用意されていないため、サードパーティー製のコネクタを用意する必要があったので、インストールしました(˶ ・ᴗ・ )੭
環境
- OS:Windows 10 Pro (インストール再現のためWindowsサンドボックス使用)
- 開発環境:Visual Studio 2019
- データベース:MySQL 5.7
前提
特になし
作業手順
今回は、開発環境側でインストールをしてみます。私のメインの環境にすでにC#でMySQLが使える状態だったので、インストールはWindowsサンドボックスで再現することにしました(* ॑꒳ ॑* )⋆*
Visual StudioとMySQLのインストール
Visual Studio 2019のインストール
Visual Studioは短期間に2015→2017→2019…とサイクル期間が短いようですが、たぶん他のVisual Studioのバージョンでもいけると思いますが、私は2019を使っています
そのままデフォルトでインストールしました( ˙꒳˙ᐢ )
ちなみにC#を使う項目はすべてインストール選択していますMySQLのインストール
MySQL 8.0はLinuxでサーバー構築で使いまくったけど、Windows用に置いてあるのが5.7だったので、5.7の方を使いました
「Developer Default」を選択してインストール。開発向けデフォルトでは、画面のように「MySQL Connectors」が項目としてピックアップされていて、Javaや.NET、C/C++などに対応しています。
Visual Studioで使用する
参照を追加してみる
Visual Studioを起動して、新規のC#フォームアプリケーションプロジェクトを作成。
そうすると、ソリューションエクスプローラーに「参照」があるので、参照を追加して「参照マネージャー」を開く。「アセンブリ」の中に実際自動で認識してくれるので、参照マネージャーで、右上の検索画面に「mysql」を入力すると、↑の画面のように「MySql.Data」が何行も出てくるので、とりあえず1つだけ、どれでもいいので選択して(行左にマウスを当てると出てくるチェックボックスをON)「OK」を選択すると…
「MySql.Data」が追加されました(*˘꒳˘*)
この中にMySQLを扱うC#オブジェクトが入っているのです。ソースで記述する
実際にソースで使うには、最初に「using」で指定しておくと便利だったので、私はそうしました
sample1.csusing System; using System.text; …(中略)… using MySql.Data.MySqlClient; // これがMySQLを扱うためのオブジェクトを含んでいる namespace WindowsForms1 { class sample1 { public void sampleMethod() try { // 接続情報を文字列で与える string connStr = "server=127.0.0.1;user id=test;password=test1;database=manutest"; MySqlConnection conn = new MySqlConnection(connStr); // 接続を開く conn.Open(); // ここにSQLの処理を書く // 接続を閉じる conn.Close(); } catch (MySqlException mse) { // MySqlの接続エラー処理をここに書く } } } }こういう流れでソースを書いていくもので、実際にMySQL ConnectorsのC#に関する公式の根拠が出回っていなかったので、第三者の情報と実際Visual Studioのコーディングでポップアップされるトピックを頼りにするしかなかったのです…( ´ •̥ ̫ •̥ ` )
実際エラーがなく基本的なコーディングの流れはつかめた(˶ ・ᴗ・ )੭⚐⚑
次回
Visual StudioにMySQLを導入できたので、次は実際にMySQLに接続して、データのやりとりも記事にまとめる予定です٩(.› ‹.♡)۶
参考文献
1. MySQL Connector/NETを使ってみよう
2. C#からMySQLに接続する - 電脳産物
3. 【Visual Studio】C#からMySqlの使い方 接続するには?SQL文を実行するには? - 困ったー
4. C#でMySQLからSELECTした結果を取り出したい