20200121のMySQLに関する記事は5件です。

MySQLのtimestampのデータが勝手に更新されてる

現象

> update users set status = 9, modified = now() where id = 1;

上記を叩いてきちんと更新されているか確認してみると、modifiedだけではなくcreatedまで更新されてしまった。。

-- 元々のデータ
> select * from users;
*************************** 1. row ***************************
   user_id: 1
    status: 1
   created: 2015-05-26 04:01:21
  modified: 2018-03-03 05:54:54

-- 更新したデータ
> select * from users;
*************************** 1. row ***************************
   user_id: 1
    status: 9
   created: 2020-01-21 00:00:00 -- あれ、こっちまで更新されてる。。
  modified: 2020-01-21 00:00:00

原因

結論、createdCURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPで設定されているからでした。

> show create table users\G
*************************** 1. row ***************************
       Table: users
Create Table: CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `status` tinyint(4) NOT NULL,
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPがあるとupdate文をかけた時に自動更新されるような設定なため、勝手にcreatedも更新されていたようです。
timestamp型は、デフォルトでCURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPが付いてしまうらしい?

無効化

下のsqlを叩いて自動更新を無効化しました。

> alter table users modify created timestamp default '1970-01-01 00:00:01'
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Redmine のmysqlでAccess Deniedにはまった記録(低次元ミスでとても恥ずかしいが人柱で)

ちまたのWin Server 2008サポート切れに伴いWin Server 2016へ最新版Bitnami redmine 4.1をインストールし移行・・のためここを参考にmysqlのテーブル削除をトライするがmysqlのログインで弾かれる。

>mysql -u root -p
>Access denied for user 'root'@'localhost' (using password: YES)

ググると同問題遭遇者が累々多数。
ほとんどがrootのパスワード再設定で解決のよう。
でもusing password: YESだからパスワード問題でないのでは?意図的にパスワード外すとusing password: NOって返るし。YESってことはパスワード問題でない?
でもネットにはAccess deniedでパスワード再設定以外は参考例なく1日半、調べてはトライの繰り返しで徒労に過ぎ。

まずは旧環境でダンプ取れるのがユーザがbitnamiなので-u bitnamiでやるが同じ

TCP port番号を明記してやると通るような事例もあり --port 3306明記でやるが同じ

環境変数でINSTALLDIRが必要の事例ありなかったので作成するが同じ

-D付きでDBをbitnamiと明示してやると・・・でも同じ

ということで結局Bitnami redmineをアンインコ、再インスコして初期パスワードをセットすると問題なくログインできた

結局恥ずかしい理由は・・

初期ユーザ名設定をadminとパスワードセットしRedmineにadminで初回サインイン時にパスワード変更となりその変更したパスワードでmyselへログインしようとした、でrootのパスワード誤りが原因でした

Redmineインストール時のパスワード必ずメモで残すべし、それがmysqlのパスワードなので・・・

あー恥ずかしい

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MySQL/PostgreSQLバージョン別利用できるプロダクト

MySQLのDBエンジンのバージョンで、Alibaba Cloudの使えるマネージドデータベースプロダクトが変わってくるのでリストにしてみたよ。(Alibaba Cloud International ベース)

コンソールベースで確認したのでドキュメントよりも新しいです。(2020年1月21日現在)

Engine RDS Basic RDS HA RDS Enterprise POLARDB
MySQL8.0
MySQL5.7 ×
MySQL5.6 ×
MySQL5.5 × × ×
Engine RDS Basic RDS HA POLARDB
PostgreSQL 12 × ×
PostgreSQL 11
PostgreSQL 10 ×
PostgreSQL 9.4 × ×

ApsaraDB for RDS edition overview
https://www.alibabacloud.com/help/doc-detail/55665.htm
(2020年1月21日現在最新に追いついてない様子)

ApsaraDB for POLARDB
https://www.alibabacloud.com/ja/products/apsaradb-for-polardb

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails6の複数DBを試してみた

Rails6からActive Record で複数のデータベースが利用できるようになった。

この機能はモノリシックなシステムをマイクロサービス化していく過程でも有効で、アプリケーションをロジック・データを順番に分けていく時に活用できる。(参考: IBM Developerサイト / マイクロサービス、SOA、API:味方か敵か / 図5.モノリシック・アプリケーションからマイクロサービスへ

今回はベースとなるアプリケーション(Dogs)を作成し、そのデータを別の新しいアプリケーション(Cats)から参照して処理するケースを仮定して試してみる。

環境

$ ruby -v
ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin19]
$ gem -v
3.0.6
$ rails -v
Rails 6.0.2.1
$ mysql -u root -e 'select version();'
+-----------+
| version() |
+-----------+
| 8.0.18    |
+-----------+

ベースアプリケーション(Dogs)の作成

まずRailsアプリケーションを作成し、プロジェクトルートに移動する

$ rails new -T -d mysql dogs
$ cd dogs

次に何かデータを入れたいので、チワワ(Chihuahua)のモデルを作成する

$ bundle exec rails g model Chihuahua name:string

Running via Spring preloader in process 22237
      invoke  active_record
      create    db/migrate/20200119010243_create_chihuahuas.rb
      create    app/models/chihuahua.rb

1つだとつまらないので、プードル(Poodle)のモデルも作成する

$ bundle exec rails g model Poodle name:string

Running via Spring preloader in process 22245
      invoke  active_record
      create    db/migrate/20200119010313_create_poodles.rb
      create    app/models/poodle.rb

DBを作成・マイグレーションする

$ bundle exec rake db:create db:migrate

Created database 'dogs_development'
Created database 'dogs_test'
== 20200119010243 CreateChihuahuas: migrating =================================
-- create_table(:chihuahuas)
   -> 0.0098s
== 20200119010243 CreateChihuahuas: migrated (0.0099s) ========================

== 20200119010313 CreatePoodles: migrating ====================================
-- create_table(:poodles)
   -> 0.0116s
== 20200119010313 CreatePoodles: migrated (0.0117s) ===========================

チワワとプードルに各々データを登録する

$ bundle exec rails r 'Chihuahua.create!(name:"ちくわ")'
$ bundle exec rails r 'Chihuahua.create!(name:"わんこ")'
$ bundle exec rails r 'Poodle.create!(name:"しらたま")'

データが登録できたか確認する。

$ bundle exec rails r 'p Chihuahua.all'

Running via Spring preloader in process 22407
#<ActiveRecord::Relation [#<Chihuahua id: 1, name: "ちくわ", created_at: "2020-01-19 01:11:49", updated_at: "2020-01-19 01:11:49">, #<Chihuahua id: 2, name: "わんこ", created_at: "2020-01-19 01:11:50", updated_at: "2020-01-19 01:11:50">]>
$ bundle exec rails r 'p Poodle.all'

Running via Spring preloader in process 22409
#<ActiveRecord::Relation [#<Poodle id: 1, name: "しらたま", created_at: "2020-01-19 01:11:51", updated_at: "2020-01-19 01:11:51">]>

チワワに2件、プードルに1件登録されていることを確認する

新しいアプリケーション(Cats)の作成

別の新しいアプリケーション(Cats)を隣のパスに作成する

$ cd ../
$ rails new -T -d mysql cats
$ cd cats

そこにも同様にデータを入れたいので、アメリカンショートヘア(AmericanShortHair)のモデルを作成する

$ bundle exec rails g model AmericanShortHair name:string

Running via Spring preloader in process 22466
      invoke  active_record
      create    db/migrate/20200119011624_create_american_short_hairs.rb
      create    app/models/american_short_hair.rb

DBを作成・マイグレーションする

$ bundle exec rake db:create db:migrate

Running via Spring preloader in process 22466
      invoke  active_record
      create    db/migrate/20200119011624_create_american_short_hairs.rb
      create    app/models/american_short_hair.rb
Created database 'cats_development'
Created database 'cats_test'
== 20200119011624 CreateAmericanShortHairs: migrating =========================
-- create_table(:american_short_hairs)
   -> 0.0097s
== 20200119011624 CreateAmericanShortHairs: migrated (0.0098s) ================

アメリカンショートヘアに2件のデータを登録する

$ bundle exec rails r 'p AmericanShortHair.create!(name:"とら")'

Running via Spring preloader in process 22487
#<AmericanShortHair id: 1, name: "とら", created_at: "2020-01-19 01:16:55", updated_at: "2020-01-19 01:16:55">

$ bundle exec rails r 'p AmericanShortHair.create!(name:"たま")'

Running via Spring preloader in process 22489
#<AmericanShortHair id: 2, name: "たま", created_at: "2020-01-19 01:16:56", updated_at: "2020-01-19 01:16:56">

正常に登録できていることを確認する

$ bundle exec rails r 'p AmericanShortHair.all'

Running via Spring preloader in process 22492
#<ActiveRecord::Relation [#<AmericanShortHair id: 1, name: "とら", created_at: "2020-01-19 01:16:55", updated_at: "2020-01-19 01:16:55">, #<AmericanShortHair id: 2, name: "たま", created_at: "2020-01-19 01:16:56", updated_at: "2020-01-19 01:16:56">]>

新しいCatsアプリケーションからベースアプリケーション(Dogs)のデータを参照する

以降はRailsガイドを参考に進める。

まずはdatabase.yml をバックアップし、プレーンな設定のみ入れておく

$ mv config/database.yml{,.org}
$ cat <<'EOT' > config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  host: localhost

development:
  <<: *default
  database: cats_development
EOT

この状態でアメリカンショートヘアに登録されている2件のデータが表示されている

$ bundle exec rails r 'p AmericanShortHair.all'

Running via Spring preloader in process 22626
#<ActiveRecord::Relation [#<AmericanShortHair id: 1, name: "とら", created_at: "2020-01-19 01:16:55", updated_at: "2020-01-19 01:16:55">, #<AmericanShortHair id: 2, name: "たま", created_at: "2020-01-19 01:16:56", updated_at: "2020-01-19 01:16:56">]>

Catsのデータベースをprimaryとして設定する

$ cat <<'EOT' > config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  host: localhost

development:
  primary:
    <<: *default
    database: cats_development
EOT

この状態でもちゃんとアメリカンショートヘアに登録されている2件のデータが表示されている

$ bundle exec rails r 'p AmericanShortHair.all'

Running via Spring preloader in process 22634
#<ActiveRecord::Relation [#<AmericanShortHair id: 1, name: "とら", created_at: "2020-01-19 01:16:55", updated_at: "2020-01-19 01:16:55">, #<AmericanShortHair id: 2, name: "たま", created_at: "2020-01-19 01:16:56", updated_at: "2020-01-19 01:16:56">]>

新しいCatsアプリケーションにDogsのモデルをコピーする

$ cp -rf ../dogs/app/models app/models/dogs

DogsのモデルはCatsとは別のデータベースを参照するので、基底クラスをApplicationRecordを継承した別クラスに置き換える

$ rm -rf app/models/dogs/application_record.rb app/models/dogs/concerns
$ cat <<'EOT' > app/models/dogs/base.rb
class Dogs::Base < ApplicationRecord
  self.abstract_class = true
  connects_to database: { writing: :dogs }
end
EOT

各モデルクラスを前項で作成したDogs::Baseを継承する形に変更し、Dogsモジュール配下に入れる

$ find app/models/dogs -type f -name '*.rb' -print0 | xargs -0 sed -i.bak -e "s/^\(class\) \([^ ]*\) <.*/\1 Dogs::\2 < Dogs::Base/g"
$ find app/models/dogs -type f -name '*.bak' -print0 | xargs -0 rm

新しいCatsアプリケーションにDogsのマイグレーションファイルをコピーする

$ cp -rf ../dogs/db/migrate db/dogs_migrate

最後に database.yml にdogsのデータベースを追加する

$ cat <<'EOT' > config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  host: localhost

development:
  primary:
    <<: *default
    database: cats_development
  dogs:
    <<: *default
    database: dogs_development
EOT

これで一通り設定は完了。
以降でデータが取得できることを確認していく。

もともとCatsアプリケーションにあったアメリカンショートヘアのデータが取得できている

$ bundle exec rails r 'p AmericanShortHair.all'

Running via Spring preloader in process 22723
#<ActiveRecord::Relation [#<AmericanShortHair id: 1, name: "とら", created_at: "2020-01-19 01:16:55", updated_at: "2020-01-19 01:16:55">, #<AmericanShortHair id: 2, name: "たま", created_at: "2020-01-19 01:16:56", updated_at: "2020-01-19 01:16:56">]>

加えて新しいCatsアプリケーションからDogsの各データが取得できるようになっている

$ bundle exec rails r 'p Dogs::Chihuahua.all'

Running via Spring preloader in process 23116
#<ActiveRecord::Relation [#<Dogs::Chihuahua id: 1, name: "ちくわ", created_at: "2020-01-19 01:11:49", updated_at: "2020-01-19 01:11:49">, #<Dogs::Chihuahua id: 2, name: "わんこ", created_at: "2020-01-19 01:11:50", updated_at: "2020-01-19 01:11:50">]>
$ bundle exec rails r 'p Dogs::Poodle.all'

Running via Spring preloader in process 23118
#<ActiveRecord::Relation [#<Dogs::Poodle id: 1, name: "しらたま", created_at: "2020-01-19 01:11:51", updated_at: "2020-01-19 01:11:51">]>

これでベースとなるアプリケーション(Dogs)のデータを、別の新しいアプリケーション(Cats)から参照することができた。

所感

これでデータストアを共通化した状態でロジックだけ新しいアプリに移すことが可能になるが、この実装ではリスクが高いと考える。

例えば、複数のアプリケーション1つのデータストアを触ることで、本来意図しないデータベースの更新が発生する(コールバック系の処理とか危なそう)であったり、参照しているモデルやマイグレーションファイルに更新が起きたとき、意図しない不整合が起きる(参照してる側が知らないうちにモデルやDBスキーマが変わってたとか・・・)であったりと言ったことが起きると考えられる。

この仕組みを導入するからには、最終的にはきっちりとしたマイクロサービスにしてデータの受け渡しはちゃんとAPI経由で行う仕切りにするか、モデルだけ別ライブラリに切り出してJavaのDAOクラス的な物として使うか……意外と後者側の方が使い勝手がいいかもしれない。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

docker-composeでMySQLのrootパスワードを忘れた場合

docker-composeでMySQLのrootパスワードを忘れた場合に自分が行った対処のメモです。

権限なしでmysqlコンテナを起動する

パスワードをリセットするためには権限テーブルを非参照で起動する必要があります。下記のオプションをdocker-compose.ymlに追加。
command: mysqld --skip-grant-tables --skip-networking

docker-compose.yml
mysql:
      build:
        context: ./mysql
        args:
          - MYSQL_VERSION=${MYSQL_VERSION}
      environment:
        - MYSQL_DATABASE=${MYSQL_DATABASE}
        - MYSQL_USER=${MYSQL_USER}
        - MYSQL_PASSWORD=${MYSQL_PASSWORD}
        - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
        - TZ=${WORKSPACE_TIMEZONE}
      command: mysqld --skip-grant-tables --skip-networking 
      volumes:
        - ${DATA_PATH_HOST}/mysql:/var/lib/mysql
        - ${MYSQL_ENTRYPOINT_INITDB}:/docker-entrypoint-initdb.d
      ports:
        - "${MYSQL_PORT}:3306"
      networks:
        - backend

コンテナを再起動し、変更を反映させます。

>docker-compose stop mysql
>docker-compose up -d mysql

パスワード変更

mysqlコンテナに入る
>docker-compose exec mysql bash

パスワードなしでログインできるようになる
mysql> mysql -u root

ユーザ名、ホスト名を確認
mysql> use mysql;
mysql> SELECT user, host FROM user;

パスワードを変更
mysql> SET PASSWORD FOR ユーザ名@ホスト名 = 'パスワード';

最後にcommand: mysqld --skip-grant-tables --skip-networkingをdocker-compose.ymlから削除し、再起動すれば完了。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む