20211125のMySQLに関する記事は3件です。

Amazon Aurora(MySQL)のALTER文のLockを調べてみた

本記事は、Craft Egg Advent Calendar 2021の12/1の記事です。 はじめに MySQLを運用していく中で、ALTER文を流したいタイミングがたまにあります。 しかしLockがかかって大変なことになるのでは?とおもい、ALTER文ながすことをためらうことばかりでした。 Amazon Aurora MySQL3(MySQL8.0互換)がリリースされたこともあり、最近のMySQLのALTER文の改善をみていこうとおもいます。 調査対象のAmazon Auroa(MySQL)のバージョン 以下の3つのバージョンです。 Engine version (a) 5.6.mysql_aurora.1.23.4 (b) 5.7.mysql_aurora.2.10.1 (c) 8.0.mysql_aurora.3.01.0 調査するALTER文(LockがかかりそうなDDL) 次の4つのパターンを調査します。 (1) カラム追加 次のようのなSQLです。 alter table `テーブル名` add `カラム名` '型'; (2) インデックスの作成 次のようなSQLです。 CREATE INDEX `インデックス名` ON `テーブル名` (`カラム名`) ; (3) VARACHAR型のカラムサイズの伸長 次のようなSQLです。 ALTER TABLE `テーブル名` CHANGE COLUMN `カラム名` `カラム名` VARCHAR(6); (4) パーティションの追加 次のようなSQLです(RANGE PARTITIONを想定) ALTER TABLE `テーブル名` ADD PARTITION (PARTITION `パーティション名` VALUES LESS THAN (5000)) ; 選出理由 ALTER文を流そうと思った時にためらいそうなもののなかで、MySQLのバージョンがあがるにつれ、改善されたALTER文を選んでいます。 それぞれの期待する結果は、次の通りです。 MySQL5.6 MySQL5.7 MySQL8.0 (1)カラム追加 ○ ○ ○ (2)インデックスの作成 ○ ○ ○ (3)VARACHAR型のカラムサイズの伸長 × ○ ○ (4)パーティションの追加 × × ○ ※○はLockがかからないことを示します(Meta Data Lockをのぞく) 参考 ・MySQL5.6に関してのLock ・MySQL5.7に関してのLock ・MySQL8.0に関してのLock テスト対象のテーブルの準備 今回検証するにあたり、データの準備をしていきます。 公式ドキュメントのオンライン DDL 実験のためのスキーマ設定コード の手順にしたがってテーブルとデータを用意します。 せっかく検証するのであれば、データ量がおおいほうがいいよね、とおもい(後々の後悔しましたが) 上記のドキュメントを参考に big_table というテーブルに 122,486,784 レコード(約1億レコード)データをいれました。(mysqldumpの出力結果が 22GB ほどになりました・・・) big_table の show create table の出力は次のとおりです。 Create Table: CREATE TABLE `big_table` ( `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '', `TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `COLUMN_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `ORDINAL_POSITION` bigint(21) unsigned NOT NULL DEFAULT '0', `COLUMN_DEFAULT` longtext CHARACTER SET utf8, `IS_NULLABLE` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '', `DATA_TYPE` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `CHARACTER_MAXIMUM_LENGTH` bigint(21) unsigned DEFAULT NULL, `CHARACTER_OCTET_LENGTH` bigint(21) unsigned DEFAULT NULL, `NUMERIC_PRECISION` bigint(21) unsigned DEFAULT NULL, `NUMERIC_SCALE` bigint(21) unsigned DEFAULT NULL, `DATETIME_PRECISION` bigint(21) unsigned DEFAULT NULL, `CHARACTER_SET_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL, `COLLATION_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL, `COLUMN_TYPE` longtext CHARACTER SET utf8 NOT NULL, `COLUMN_KEY` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '', `EXTRA` varchar(30) CHARACTER SET utf8 NOT NULL DEFAULT '', `PRIVILEGES` varchar(80) CHARACTER SET utf8 NOT NULL DEFAULT '', `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT '', `id` bigint(21) unsigned NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 実際に検証 それでは、データの準備もできたので、実際にLockの有無を検証していきます。 データ量がおおくなってしまったので、検証につかうインスタンスは、 db.r5.xlarge を使用しています。 また、Lockがかかっているか、いないかをわかりやすくするために、INSERT文を1秒毎にbig_tableに対してながしていきます。 (1) カラム追加 の検証 実際に流すのは次のSQLです。 alter table big_table add addcolumn int ,LOCK=NONE, ALGORITHM=INPLACE; (a) 5.6.mysql_aurora.1.23.4 INSERT文をながしながら、カラム追加を実行している様子です。 (左:INSERT文、右:カラム追加) こちらLockかかることなく実行できました。 (b) 5.7.mysql_aurora.2.10.1 INSERT文をながしながら、カラム追加を実行している様子です。 (左:INSERT文、右:カラム追加) こちらLockかかることなく実行できました。 (c) 8.0.mysql_aurora.3.01.0 INSERT文をながしながら、カラム追加を実行している様子です。 (左:INSERT文、右:カラム追加) こちらLockかかることなく実行できました。 (2) インデックスの作成 の検証 実際に流すのは次のSQLです。 CREATE INDEX idx_1 ON big_table (`ORDINAL_POSITION`) ; (a) 5.6.mysql_aurora.1.23.4 INSERT文をながしながら、インデックスの作成をしている様子です。 (左:INSERT文、右:インデックスの作成) こちらLockかかることなく実行できました。 (b) 5.7.mysql_aurora.2.10.1 INSERT文をながしながら、インデックスの作成をしている様子です。 (左:INSERT文、右:インデックスの作成) こちらLockかかることなく実行できました。 (c) 8.0.mysql_aurora.3.01.0 INSERT文をながしながら、インデックスの作成をしている様子です。 (左:INSERT文、右:インデックスの作成) こちらLockかかることなく実行できました。 (3) VARACHAR型のカラムサイズの伸長 の検証 実際に流すのは次のSQLです。 alter table big_table modify `TABLE_SCHEMA` varchar(128); (a) 5.6.mysql_aurora.1.23.4 INSERT文をながしながら、VARCHAR型のカラムサイズの伸長をしている様子です。 (左:INSERT文、右:VARCHAR型のカラムサイズの伸長) 想定通り、Lockがかかりました(左のINSERT文がとまっている)。 (b) 5.7.mysql_aurora.2.10.1 INSERT文をながしながら、VARCHAR型のカラムサイズの伸長をしている様子です。 (左:INSERT文、右:VARCHAR型のカラムサイズの伸長) !なんと、想定外に、Lockがかかってしまいました。 理由は後述します。(※1) (c) 8.0.mysql_aurora.3.01.0 INSERT文をながしながら、VARCHAR型のカラムサイズの伸長をしている様子です。 (左:INSERT文、右:VARCHAR型のカラムサイズの伸長) !なんと、想定外に、Lockがかかってしまいました。 こちらも理由は後述します。(※1) ※1 Lockがかかってしまった理由 正確な理由はわからなかったのですが、Lockがかからず実行できるケースもありました。 そもそもまず、SQLの見直しからです。 ALTER TABLE small_table CHANGE COLUMN `IS_NULLABLE` `IS_NULLABLE` VARCHAR(6), ALGORITHM=INPLACE, LOCK=NONE; こちらのSQLはLockがかからず実行できました(テーブル名に注目)。 実は、テーブルのレコード件数が少ないときは(4000レコード)、Lockがかららず実行できたのですが、 今回の検証用のテーブル(1億レコード)では、エラーになってしまいました。 マニュアルをよむとVARCHARの伸長には、制約があることがわかります。 レコード件数が増えたことによって、制約にひっかかっていそうです。 (4) パーティションの追加 の検証 実際に流すのは次のSQLです。 事前に次のSQLを実行してパーティションを作成します。 ALTER TABLE `small_table` PARTITION BY RANGE (`id`) ( PARTITION p1000 VALUES LESS THAN (1000), PARTITION p4000 VALUES LESS THAN (4000) ) ; その後、次のパーティションの追加のSQLを実行して検証します。 ALTER TABLE small_table LOCK=NONE, ALGORITHM=INPLACE, ADD PARTITION (PARTITION p5000 VALUES LESS THAN (5000)) ; (a) 5.6.mysql_aurora.1.23.4 INSERT文をながしながら、パーティションを追加している様子です。 (左:INSERT文、右:パーテシションの追加) 構文エラーとなり、SQLが実行できませんでした(想定通り)。 (b) 5.7.mysql_aurora.2.10.1 INSERT文をながしながら、パーティションを追加している様子です。 (左:INSERT文、右:パーテシションの追加) こちらも、サポートしていないLockというエラーがでて、実行できませんでした(想定通り)。 (c) 8.0.mysql_aurora.3.01.0 INSERT文をながしながら、パーティションを追加している様子です。 (左:INSERT文、右:パーテシションの追加) 無事、構文エラーになることもなく、Lockもかかることもなく、実行できました。 補足 検証前は、マニュアルを読んで、次のSQL(パーティションの作成)がLockなしに実行できるものだと思っていました。 ALTER TABLE `small_table` ALGORITHM=INPLACE PARTITION BY RANGE (`id`) ( PARTITION p10 VALUES LESS THAN (10), PARTITION pmax VALUES LESS THAN MAXVALUE ) ; しかし、サポートされているのは、あくまで ADD PARTITION のため、上記SQLは構文エラーとなります。 まとめ 実際に検証した結果をまとめると次のようになります。 MySQL5.6 MySQL5.7 MySQL8.0 (1)カラム追加 ○ ○ ○ (2)インデックスの作成 ○ ○ ○ (3)VARACHAR型のカラムサイズの伸長 × △ △ (4)パーティションの追加 × × ○ △:実行できる場合もある(制約によって実行に失敗する) おわりに 昔からのMySQLの先入観で、基本的にALTER文はLockがかかってしまうとおもっていました。 しかし今回あらためて、マニュアルを見て、LockのかからないALTER文が増えていることに気づきました。 実際に実行してみると、Lockは、かからず、MySQLに対する先入観が覆されました。 また、新しいバージョンでLockがかからないALTER文は増えているのは検証を進める中でわかったのですが、 制約があるために、使えそうな機会は狭そうというのが正直なところです。 今回の検証が皆様の役に立てればと思います。 明日は@ishiguro_takuyaの記事です!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

mysqlのパスワードを変える方法

背景 AWSのEC2にデプロイするためにmysqlに入ろうとしたがパスワードが間違っていて入れず、パスワードを思い出すこともできなかったので再設定しました。 /etc/my.cnf vimで/etc/my.cnfを開き、[mysqld]の下にskip-grant-tablesと書きます。 /etc/my.snf [myaqld] skip-grant-tables mysqlを再起動 mysqlを再起動します。 sudo service mysqld restart mysqlに接続 mysql -u root mysqlに接続し、以下のように入力することでDB内のテーブルを再読み込みします。 mysql> flush privileges; 新しいパスワードを設定! alter user 'root@localhost' identified by '新しいパスワード' 新しいパスワードを設定したらDBから退出し、 mysql> quit vim /etc/my.cnf内のskpip-grant-tablesを削除します。(あるいはコメントアウト) そしてmysqlを再起動します。 ついに接続! mysql -u root -p を入力し、先ほど作成したパスワードで接続できれば、パスワードの再設定は成功です!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

モダンフロントとLaravelでCRUD処理をやってみる

はじめに 【マイスター・ギルド】本物の Advent Calendar 2021の4日目の記事です。 他にもROCKな記事ばっかりなので要チェック!!! 本記事は筆者が以下の2つの記事を自身の学習用にまとめたものです。 大変参考にさせていただきました。ありがとうございます。 『Laravel CRUD』 『LaravelでCRUD』 モダンフロントとLaravelの組み合わせを想定しているので、bladeは使いません。 フロント部分についてはコードは載せますが、詳細は触れません。 Laravel側へリクエスト投げていれば何でも大丈夫です。今回はReactとaxiosを用います。 執筆の経緯 LaravelでCRUDをやってみたいが、bladeを使っている記事ばかり。 モダンフロントとLaravelの記事が少ない・・・。 なかったら作れ!(ハック精神) 想定読者 前回の記事で環境構築された方。 記事の通りに環境構築された場合はバージョンは以下になっているはず。 PHP : 7.3.32 Composer : 2.0.14 Laravel : 6.20.41 Laravel初心者の方。 LaravelおよびMVCモデルの基礎について簡単に理解している前提で話を進めます。 今回のゴール 簡単なCRUD処理を実装する。 タスク管理アプリを作る。 実行環境 PC : MacBookAir(M1, 2020) OS : macOS Big Sur11.4 チップ : Apple M1 メモリ : 16GB DockerDesktop : 3.5.2 Docker : 20.10.7 目次 何を作るか Laravelの前準備 処理のイメージ Controllerを作成する。 web.phpを編集し、ルーティングを設定する。 .envを編集する Modelおよびmigrationを作成し、テーブルを作成する Seederを作成して実行し、サンプルレコードを作成する フロントエンドの完成形 【要件1の実装】データベースからレコードを読み込む(Read) 【要件2の実装】データベースへレコードを挿入する(Create) 【要件3の実装】データベースの情報を更新する(Update) 【要件4の実装】データベースの情報を削除する(Delete) リポジトリ 何を作るか 簡単なタスク管理アプリを作成します。簡単な要件は以下の通り。 【要件1】ページ遷移時にデータベースから既存のタスクがfetchされている。 【要件2】タスクを追加することができる。 【要件3】「変更する」ボタンを押下すると状況が「作業中」と「完了」のトグルで入れ替わる。 【要件4】「削除する」ボタンを押下するとタスクが削除される。もちろんDBからも消えている。 Laravelの前準備 Laravelの処理の簡単なイメージ とりあえずModel、View、Controller、Route、DBが分かっていればOK。小売店と卸問屋で例えてみましょう。 View ブラウザ株式会社という小売店のスタッフ。お客さんに画面という情報を提供している。 今回はここがbladeじゃなくてReact。 Route サーバー株式会社という卸問屋の電話番。 Controller サーバー株式会社の営業マン。 Model サーバー株式会社の在庫管理の部署。 DB サーバー株式会社の倉庫。 イメージ Viewから商品問い合わせの電話が入った。 Routeが電話を受けて、担当営業マンのControllerに繋ぐ。 ControllerがModelへ在庫を確認。 ModelはDBへ在庫を確認、Viewへ発送する。 ControllerがViewへ納期を伝える。 イメージ違ってたらご指摘いただけると幸いです。 Controllerを作成する。 Controllerを作成する 中身は後ほど実装するので、とりあえず作成だけしておく。 backendコンテナの中 php artisan make:controller TodoController web.phpを編集し、ルーティングを設定する。 以下の通り設定。 これでpublic/fetch_todosにgetメソッドでリクエストが来たら、TodoControllerのfetchTodosメソッドを実行するよう設定ができている。 前述の通りcontrollerの中身は後ほど実装します。 routes/web.php Route::get('fetch_todos', 'TodoController@fetchTodos'); .envファイルを編集する Laravelプロジェクト直下にある.envファイルを以下の通り修正。 dockerは各コンテナ間のネットワークも自動で作成をしてくれている。 そのためLaravel(backendコンテナ)からMySQL(dbコンテナ)へサービス名でアクセスできるようになっている。 つまり「DB_HOST」の値は「db」でOK。 .env(一部抜粋) DB_CONNECTION=mysql // dockerで環境構築した場合は、docker-compose.ymlデータベースのコンテナのサービス名を入力する。 DB_HOST=db DB_PORT=3306 // 任意のデータベース名。先にDBコンテナに入ってデータベースだけは作成しておくこと。 DB_DATABASE=tasuku // rootユーザーは初期設定で存在しているので、このままでOK。 DB_USERNAME=root // docker-compose.ymlで設定したパスワードを入力。 DB_PASSWORD=pass Modelおよびmigrationを作成し、テーブルを作成する modelファイルとmigrationファイルを作成する migrationファイルとは簡易に書け、なおかつ複数実行可能なSQL文の集まりのようなものです。 -mオプションをつけることで、modelと一緒にmigrationも作成されます。 今回はタスクを格納するtodosテーブルのみ作成します。 model名は単数形にすること。(migrationファイルは複数形名で自動生成されている) ってことはmodelはきっとテーブルの各レコードってことなんだろうか。 backendコンテナ内 php artisan make:model Models/Todo -m migrationファイルを編集 ->nullable(false)のような書き方をすることで、該当のカラムにオプションを付与します。 私はいつも頭の中でSQLを思い浮かべてからどう書くのか検索したりしてます。 database/migrations/(作成時の日時)_create_todos_table.php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateTodosTable extends Migration { public function up() { Schema::create('todos', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('name', 255)->nullable(false); $table->string('status', 255)->nullable(false); $table->timestamps(); }); } public function down() { Schema::dropIfExists('todos'); } } migrationを実行 事前にdbコンテナ内で.envで指定したデータベースを作成しておかないとエラーになるので注意。 実行したらdbコンテナ内でテーブルができているか確認。 SQLポチポチ叩かなくて良いので便利! backendコンテナ内 php artisan migrate Seederを作成して実行し、サンプルレコードを作成する Seederファイルを作成する Seederファイルとはサンプルのデータを作成できるファイル。 さっきのmigrationがcreate table文の簡易版とすると、seederはinsert文の簡易版。 backendコンテナ内 php artisan make:seeder TodosTableSeeder Seederファイルを編集 適当にファイルを作成する。 id,created_at,updated_atはSeederには入力不要。 初期だとDBがimportされていないので、追記すること。 database/seeds/TodosTableSeeder.php use Illuminate\Support\Facades\DB; use Illuminate\Database\Seeder; class TodosTableSeeder extends Seeder { public function run() { DB::table('todos')->insert( [ [ 'name' => '買い物', 'status' => '作業中' ], [ 'name' => '料理', 'status' => '作業中' ], [ 'name' => '洗濯', 'status' => '作業中' ] ] ); } } DatabaseSeederへの登録 後述のseedコマンドを実行すると、このファイルが実行される。 つまりこのファイルに先ほど作成したSeederを記載しないと意味なし。 database/seeds/DatabaseSeeder.php use Illuminate\Database\Seeder; class DatabaseSeeder extends Seeder { /** * Seed the application's database. * * @return void */ public function run() { $this->call(TodosTableSeeder::class); } } Seederファイルの実行 dbコンテナにデータが入っていることを確認。 backendコンテナ内 php artisan db:seed フロントエンドの完成形 一部抜粋です。完成系は本記事の終わりのgithub参照。何やっているか雰囲気だけ掴んでもらえれば。 Reactで書いてますが、画面表示時にLaravelへgetメソッド投げれたら何でも良いです。 Vue.jsの場合はcreated()にfetchTodosメソッド、それ以外のメソッドはv-onで制御すればOKかと思います。 バニラJSの場合はaddEventListener駆使してください。 Main.tsx import { useState, useEffect, ChangeEvent } from 'react' import { client, postMethod } from './lib/axios' import { createURLSearchParams } from './utils' interface TodoType { id: string name: string status: string } const WORK_IN_PROGRESS = '作業中' const DONE = '完了' export const Main = () => { const [todos, setTodos] = useState<TodoType[]>([]) const [todoName, setTodoName] = useState('') const bindTodoNameValue = (event: ChangeEvent<HTMLInputElement>) => { setTodoName(event.target.value) } // 要件1 const fetchTodos = async () => { const { data } = await client.get<TodoType[]>('/fetch_todos') setTodos(data) } useEffect(() => { fetchTodos() }, []) // 要件2 const pushTodo = () => { const params = createURLSearchParams<TodoType>([ ['name', todoName], ['status', WORK_IN_PROGRESS], ]) postMethod('push_todo', params).then((_response) => fetchTodos()) } // 要件3 const changeStatus = (id: string, status: string) => { const statusParam = status === WORK_IN_PROGRESS ? DONE : WORK_IN_PROGRESS const params = createURLSearchParams<TodoType>([ ['id', id], ['status', statusParam], ]) postMethod('change_status', params).then((_response) => fetchTodos()) } // 要件4 const deleteTodo = (id: string) => { const params = createURLSearchParams<TodoType>([['id', id]]) postMethod('delete_todo', params).then((_response) => fetchTodos()) } return ( <> <p>タスクを追加する</p> <input onChange={bindTodoNameValue} type="text" /> <button onClick={pushTodo}>追加する</button> <ul> {todos.length > 0 && todos.map(({ id, name, status }, index) => { return ( <li key={id}> <p>Index:{index + 1}</p> <p>タスク名:{name}</p> <p>状況:{status}</p> <button onClick={() => changeStatus(id, status)}> 変更する </button> <button onClick={() => deleteTodo(id)}>削除する</button> </li> ) })} </ul> </> ) } 【要件1の実装】データベースからレコードを読み込む(Read) 処理が簡単なので、まずはReadからやります。 TodoControllerを以下の通り実装。 header("Access-Control-Allow-Origin: *")を付けないとCSRFのエラーが出ます。 簡単に言うと「違うドメインから通信来ても受け入れるよ」という設定です。 本来はちゃんとした設定をしないといけないんですが、今回は省略します。 migrationの時と似たような書き方でselect文を書いているイメージです。 json形式に変換してレスポンスを返します。 Todo::select()のようにModelを利用してDBへアクセスしていますが、DBから直接取ってくる実装方法もあります。 役割を考えると、Modelを利用するべきではと考えています。 TodoController.php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; class TodoController extends Controller { public function fetchTodos() { header("Access-Control-Allow-Origin: *"); $todos = Todo::select('id' ,'name', 'status')->get(); return json_decode($todos); } } 画面をリロードしてみて、きちんとfetchできているか確認。 Chromeのdeveloperツールでも確認。200番返ってきてますね。 【要件2の実装】データベースへレコードを挿入する(Create) web.phpを編集してルーティングを追加 クライアント側から情報を受け取る時は大事な情報が入っている場合もあるでしょうから、post通信にします。 ちなみにそのままaxiosでLaravelにPOSTすると、エラーコード419が返ってきます。 これはCSRFトークンが埋め込まれていないためのエラーです。 app/Http/Kernel.phpの$middlewareGroupsの\App\Http\Middleware\VerifyCsrfToken::classをコメントアウトすれば一旦解決。 根本解決するにはリクエスト内にCSRFトークンを埋め込む必要がある。(勉強中) bladeを使用する場合はとても簡単に解決可能ですが、Laravelでフロント作る気になれなかったので今回は割愛。 routes/web.php <?php Route::get('fetch_todos', 'TodoController@fetchTodos'); // 追加 Route::post('push_todo', 'TodoController@pushTodos'); TodoControllerを以下の通り実装 フロント側から受け取った情報は$request内に格納されている。 $todo = new Todo()でModelの新しい営業担当を呼び出したイメージ。 $requst->input('name')はバニラPHPで言えば、$_POST['name']というところ。 $todo->save()でDBに格納できる。 TodoController.php <?php namespace App\Http\Controllers; // 追加 use App\Models\Todo; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; class TodoController extends Controller { public function fetchTodos() { header("Access-Control-Allow-Origin: *"); $todos = Todo::select('id' ,'name', 'status')->get(); return json_decode($todos); }   //追加 public function pushTodo(Request $request) { header("Access-Control-Allow-Origin: *"); $todo = new Todo(); $todo->name = $request->input('name'); $todo->status = $request->input('status'); $todo->save(); } } フロント側から適当にタスクを追加する。 200番が返ってきていることを確認。Laravel側で何も返していないので、dataは空でOK。 リロードしても今追加したタスクが消えないことを確認。 【要件3の実装】データベースの情報を更新する(Update) web.phpを編集してルーティングを追加 routes/web.php <?php Route::get('fetch_todos', 'TodoController@fetchTodos'); Route::post('push_todo', 'TodoController@pushTodo'); // 追加 Route::post('change_status', 'TodoController@changeStatus'); TodoControllerを以下の通り実装 $id = (int) $request->input('id')でフロント側からきているidはstring型なので、int型へ型キャスト。 $todo = Todo::find($id)でTodoModelへ「$idを満たすレコードを頂戴」と言っている。 今回はstatusだけを変更したいので、上書きして保存。 TodoController.php <?php namespace App\Http\Controllers; use App\Models\Todo; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; class TodoController extends Controller { public function fetchTodos() { header("Access-Control-Allow-Origin: *"); $todos = Todo::select('id' ,'name', 'status')->get(); return json_decode($todos); } public function pushTodo(Request $request) { header("Access-Control-Allow-Origin: *"); $todo = new Todo(); $todo->name = $request->input('name'); $todo->status = $request->input('status'); $todo->save(); } // 追加 public function changeStatus(Request $request) { header("Access-Control-Allow-Origin: *"); $id = (int) $request->input('id'); $todo = Todo::find($id); $todo->status = $request->input('status'); $todo->save(); } } フロント側で「変更ボタン」を押下して、「状況」が変わることを確認。 200番が出ていることも確認。 リロードしても「状況」が「完了」のままだと確認。 【要件4の実装】データベースの情報を削除する(Delete) web.phpを編集してルーティングを追加 routes/web.php <?php Route::get('fetch_todos', 'TodoController@fetchTodos'); Route::post('push_todo', 'TodoController@pushTodo'); Route::post('change_status', 'TodoController@changeStatus'); // 追加 Route::post('delete_todo', 'TodoController@deleteTodo'); TodoControllerを以下の通り実装 delete()でレコード削除。 TodoController.php <?php namespace App\Http\Controllers; use App\Models\Todo; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; class TodoController extends Controller { public function fetchTodos() { header("Access-Control-Allow-Origin: *"); $todos = Todo::select('id' ,'name', 'status')->get(); return json_decode($todos); } public function pushTodo(Request $request) { header("Access-Control-Allow-Origin: *"); $todo = new Todo(); $todo->name = $request->input('name'); $todo->status = $request->input('status'); $todo->save(); } public function changeStatus(Request $request) { header("Access-Control-Allow-Origin: *"); $id = (int) $request->input('id'); $todo = Todo::find($id); $todo->status = $request->input('status'); $todo->save(); } // 追加 public function deleteTodo(Request $request) { header("Access-Control-Allow-Origin: *"); $id = (int) $request->input('id'); $todo = Todo::find($id); $todo->delete(); } } フロント側から適当にタスクを削除。 今回は「買い物」を削除してみた。 200番が返ってくることを確認。 リポジトリ https://github.com/chillout2san/laravel_crud パイセンがガッツリレビューしてくれてプルリクまで出してくれました。ギザ優しす。 そんなパイセンのアドカレ記事はこちらです→FastAPI + Reactでフルスタックアプリを作成する 終わりに 今までfirebaseしか触ったことがなかったので、バックエンド触るのは新鮮だった。 API組むの楽しすぎてハマりそう。 だがやっぱりbladeは好きになれなかった。 Laravelはドキュメントが非常に充実していてありがたい。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む