DjangoモデルをJSONで返すときは、Pythonの辞書/配列・JSON文字列・HTTP応答を区別します。変換できることと、どのユーザーのどの項目を返してよいかは別の問題です。
元の例:JSON文字列を辞書に入れるとどうなるか
初期版のUserViewはserializeで得た文字列をusersへ入れてJsonResponseへ渡していました。その結果はusersが配列ではなく文字列です。元の「jsonオブジェクトとなる」という説明だけでは、この違いが分かりません。次の表は元v2のコードを保持した資料です。delete_flagだけを権限判定とせず、Userを全fieldで公開する実装としてコピーしません。ここでいうUserは元の独自モデルで、Django標準auth.Userにdelete_flagがあるという意味でもありません。
|
from django.core import serializers
def get(self, request, *args, **kwargs): users = User.objects.filter(delete_flag=0) context = { return JsonResponse(context) |
文字列・配列・直接HTTPを比べる
次の関数には、認可済みで件数を限定したBook QuerySetだけを渡します。最初はbooksが文字列、次はbooksが配列、最後はトップレベル配列です。json.loadsで二重JSONを解消することも認可にはならず、Userの全データを変換し直して公開しません。
import json
from django.core import serializers
from django.http import HttpResponse, JsonResponse
def compare_representations(scoped_queryset):
# Call only with an authorized, bounded queryset; never serialize auth.User wholesale.
serialized = serializers.serialize("json", scoped_queryset, fields=("title", "isbn"))
return (
JsonResponse({"books": serialized}), # books is a JSON string.
JsonResponse({"books": json.loads(serialized)}), # books is an array.
HttpResponse(serialized, content_type="application/json"), # Top-level array.
)
| この記事の要点 |
|
4 つのアプローチ
| 方法 | 用途 | 長所 | 短所 |
|---|---|---|---|
1. JsonResponse 直接 | 小規模 API、単純レコード | Django標準。速度の優劣は未測定 | フィールド指定が手動 |
2. django.core.serializers | QuerySet 丸ごと | 標準同梱 | 独特なラップ形式 |
3. DRF ModelSerializer | 入力/出力を宣言するAPI | 宣言的、バリデーション付き | パッケージ追加 |
4. 自作 to_dict() | カスタム整形 | 柔軟 | メンテ負担 |
方法1: JsonResponse で直接返す
旧例の注意:この旧例には認証/所有者の絞込みや一覧件数上限がありません。getで対象がない場合の404と、published_atがnullの場合も別途扱います。JSON化しても他人の行や関連を返してよいことにはなりません。
from django.http import JsonResponse
from .models import Book
def book_detail(request, pk):
book = Book.objects.get(pk=pk)
return JsonResponse({
'id': book.id,
'title': book.title,
'isbn': book.isbn,
'published_at': book.published_at.isoformat(), # date → ISO 文字列
'author': {
'id': book.author.id,
'name': book.author.name,
},
})
# QuerySet をリストで返す
def book_list(request):
qs = Book.objects.select_related('author').all()
data = [{
'id': b.id,
'title': b.title,
'author': b.author.name,
} for b in qs]
return JsonResponse({'count': len(data), 'results': data})
# ↑ safe=False が必要な場合は: JsonResponse(data, safe=False)
safe=False の話
JsonResponse はデフォルトで辞書のみ受け付けます。リストを直接返したい場合は safe=False を付けます:
旧例の注意:safe=Falseはトップレベルに辞書以外のPython値を渡すための指定です。認可や入力の無害化ではありません。安全性の理由だけで現在のすべてのJSON配列が禁止されるわけではなく、応答形式はAPIの契約で決めます。
return JsonResponse([{'a': 1}, {'b': 2}], safe=False)
# safe=True (既定) で list を渡すと TypeError 発生
# JSON Hijacking 対策で禁止されている、ラップ推奨:
return JsonResponse({'data': [{'a': 1}, {'b': 2}]})
方法2: django.core.serializers
旧例の注意:serializeの結果はJSON文字列です。そのままHttpResponseへ渡す場合とJsonResponseの辞書に入れる場合は型が変わります。全件を無認可で返さず、対象/件数/fieldsを先に限定します。model/pk等の構造も公開API用DTOと同じとは限りません。
from django.core import serializers
from django.http import HttpResponse
from .models import Book
def book_list_json(request):
qs = Book.objects.all()
data = serializers.serialize('json', qs, fields=('title', 'isbn'))
return HttpResponse(data, content_type='application/json')
# 出力例
# [
# {"model": "library.book", "pk": 1,
# "fields": {"title": "Python入門", "isbn": "9784..."}},
# ...
# ]
独自のフォーマット(model / pk / fields)でラップされるため、フロント側が普通の JSON を期待していると扱いにくい点に注意。fixture 形式に近い。
方法3: Django REST Framework(認可とfieldを明示)
旧例の注意:追加依存の導入例であり既存の本番環境へそのままインストールする指示ではありません。既存INSTALLED_APPSや設定全体を消さず、対応版・独立した検証環境・配布手順を確認します。
pip install djangorestframework
# settings.py
INSTALLED_APPS += ['rest_framework']
実行検証したモデル・API・URLの対応
新教材は、登録ユーザーが自分のBookと自分のAuthorだけを扱う方針です。管理者の他人操作や共有は実装しません。モデル例のprivate_note/ownerは出力せず、入力にも許可しません。既存アプリのモデルやDBをこの教材へ差し替える指示ではありません。
from django.conf import settings
from django.db import models
class Author(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
name = models.CharField(max_length=80)
private_note = models.TextField(default="")
class Book(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
author = models.ForeignKey(Author, on_delete=models.PROTECT, related_name="books")
title = models.CharField(max_length=120)
isbn = models.CharField(max_length=13)
published_at = models.DateField(null=True, blank=True)
private_note = models.TextField(default="")
api.pyは通常DjangoのGET専用ビューとDRF ViewSetを含むファイル全体です。通常ビューは先頭20件だけでページングAPIではありません。DRFは一意id順の既定20/最大50件とし、author_idの入力先もrequest.userへ限定します。serializerを入力に使うときはrequest contextが必要で、ない場合はAuthorを選べない設定です。is_recentは日付null/未来を偽とし、今日から過去89日までを真と定義しました。業務ごとの定義とは別です。
from io import BytesIO
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
from django.utils import timezone
from django.views.decorators.http import require_GET
from rest_framework import serializers, viewsets
from rest_framework.authentication import SessionAuthentication
from rest_framework.exceptions import APIException, UnsupportedMediaType
from rest_framework.pagination import PageNumberPagination
from rest_framework.parsers import JSONParser
from rest_framework.permissions import IsAuthenticated
from rest_framework.renderers import JSONRenderer
from .models import Author, Book
def owned_books(user):
# A row with a foreign author's owner is also outside this teaching policy.
return Book.objects.filter(owner=user, author__owner=user).select_related("author").order_by("id")
def public_book(book):
return {
"id": book.pk, "title": book.title, "isbn": book.isbn,
"published_at": book.published_at,
"author": {"id": book.author_id, "name": book.author.name},
}
@require_GET
def book_list(request):
if not request.user.is_authenticated:
return JsonResponse({"detail": "Login required."}, status=403)
# This is a bounded first batch, NOT an automatic DRF paginated view.
return JsonResponse({"results": [public_book(book) for book in owned_books(request.user)[:20]]})
@require_GET
def book_detail(request, pk):
if not request.user.is_authenticated:
return JsonResponse({"detail": "Login required."}, status=403)
return JsonResponse(public_book(get_object_or_404(owned_books(request.user), pk=pk)))
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = Author
fields = ("id", "name")
class BookSerializer(serializers.ModelSerializer):
author = AuthorSerializer(read_only=True)
author_id = serializers.PrimaryKeyRelatedField(
queryset=Author.objects.none(), source="author", write_only=True,
)
is_recent = serializers.SerializerMethodField()
class Meta:
model = Book
fields = ("id", "title", "isbn", "published_at", "author", "author_id", "is_recent")
read_only_fields = ("id",)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
request = self.context.get("request")
if request is not None and request.user.is_authenticated:
self.fields["author_id"].queryset = Author.objects.filter(owner=request.user)
def to_internal_value(self, data):
allowed = {"title", "isbn", "published_at", "author_id"}
if not isinstance(data, dict) or set(data) - allowed:
raise serializers.ValidationError({"detail": "Expected only writable book fields."})
for field in ("title", "isbn"):
if field in data and type(data[field]) is not str:
raise serializers.ValidationError({field: "Expected a string."})
if "published_at" in data and data["published_at"] is not None and type(data["published_at"]) is not str:
raise serializers.ValidationError({"published_at": "Expected an ISO date or null."})
if "author_id" in data and (type(data["author_id"]) is not int or not 1 <= data["author_id"] <= 2147483647):
raise serializers.ValidationError({"author_id": "Expected a positive integer."})
return super().to_internal_value(data)
def get_is_recent(self, obj):
return obj.published_at is not None and 0 <= (timezone.localdate() - obj.published_at).days < 90
class BookPagination(PageNumberPagination):
page_size = 20
page_size_query_param = "page_size"
max_page_size = 50
class BodyTooLarge(APIException):
status_code = 413
default_detail = "JSON body too large."
class BoundedJSONParser(JSONParser):
def parse(self, stream, media_type=None, parser_context=None):
encoding = (parser_context or {}).get("encoding") or "utf-8"
if encoding.lower().replace("-", "") != "utf8":
raise UnsupportedMediaType(media_type)
raw = stream.read(4097)
if len(raw) > 4096:
raise BodyTooLarge()
return super().parse(BytesIO(raw), media_type, parser_context)
class BookViewSet(viewsets.ModelViewSet):
authentication_classes = (SessionAuthentication,)
permission_classes = (IsAuthenticated,)
parser_classes = (BoundedJSONParser,)
renderer_classes = (JSONRenderer,)
serializer_class = BookSerializer
pagination_class = BookPagination
def get_queryset(self):
return owned_books(self.request.user)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
通常GETは/plain/books/、DRFは/api/books/へ分けます。既存auth/session/CSRF middlewareと認証したsessionが前提で、JSONだけを受け付けます。新parserで読むJSON本文は4096byteまで/UTF-8のみです。未使用のDELETE本文等まで解析する全体のrequest容量制限や連打対策ではなく、Web層/アプリの制限や監査も別に設計します。ISBNは長さ等の文字列検査で、ISBNのチェックディジットまで実装していません。
from django.urls import include, path
from rest_framework.routers import SimpleRouter
from .api import BookViewSet, book_detail, book_list
router = SimpleRouter()
router.register("books", BookViewSet, basename="book")
urlpatterns = [
path("plain/books/", book_list),
path("plain/books/<int:pk>/", book_detail),
path("api/", include(router.urls)),
]
ModelSerializer
旧例の注意:この最初のserializer自体はfieldsを明示していますが、author_idのquerysetが全Authorを許可し、関数ビューにも認可がありません。request contextも渡していません。日付nullで失敗し、未来の日もis_recentが真になる式です。直後の新教材では入力関連も所有者へ限定します。
# serializers.py
from rest_framework import serializers
from .models import Book, Author
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = Author
fields = ['id', 'name', 'birth_date']
class BookSerializer(serializers.ModelSerializer):
author = AuthorSerializer(read_only=True) # ネスト表示
author_id = serializers.PrimaryKeyRelatedField(
queryset=Author.objects.all(), source='author', write_only=True
)
# 計算項目
is_recent = serializers.SerializerMethodField()
class Meta:
model = Book
fields = ['id', 'title', 'isbn', 'published_at',
'author', 'author_id', 'is_recent']
read_only_fields = ['id']
def get_is_recent(self, obj):
from datetime import date
return (date.today() - obj.published_at).days < 90
# views.py
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .serializers import BookSerializer
@api_view(['GET'])
def book_list(request):
qs = Book.objects.select_related('author').all()
ser = BookSerializer(qs, many=True)
return Response(ser.data)
@api_view(['POST'])
def book_create(request):
ser = BookSerializer(data=request.data)
ser.is_valid(raise_exception=True)
ser.save()
return Response(ser.data, status=201)
ViewSet + Router でフル CRUD
旧例の注意:旧ViewSetは認可指定がなく、全体設定が既定ならAllowAnyとなります。Serializerのfieldを絞るだけでは匿名CRUDや他人の行を防げません。所有者でのget_querysetと作成時ownerも必要です。
from rest_framework import viewsets
from rest_framework.routers import DefaultRouter
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.select_related('author')
serializer_class = BookSerializer
router = DefaultRouter()
router.register(r'books', BookViewSet)
urlpatterns = router.urls
# → /books/ (GET, POST), /books/<id>/ (GET, PUT, PATCH, DELETE) 自動生成
Date / UUID / Decimal の扱い
Python 標準の json.dumps() は date / datetime / Decimal / UUID をそのままシリアライズできません:
旧例の注意:日付は固定入力の例とdate.todayの実行結果を混同しません。DjangoJSONEncoderの出力形式とDRF各fieldの表現は別に確認します。JsonResponseは既定で同encoderを使いますが、モデル/QuerySetを直接変換する機能ではありません。
import json
from datetime import date
from decimal import Decimal
from uuid import uuid4
data = {'d': date.today(), 'p': Decimal('123.45'), 'u': uuid4()}
# ❌ TypeError: Object of type date is not JSON serializable
json.dumps(data)
# ✅ Django 標準のエンコーダを使う
from django.core.serializers.json import DjangoJSONEncoder
json.dumps(data, cls=DjangoJSONEncoder)
# {"d": "2025-01-15", "p": "123.45", "u": "..."}
# JsonResponse は内部で DjangoJSONEncoder を使うので OK
from django.http import JsonResponse
JsonResponse(data) # 動く
各型の出力フォーマット
| Python 型 | JSON 出力 |
|---|---|
date | "2025-01-15" |
datetime | "2025-01-15T10:00:00+09:00" |
time | "10:00:00" |
timedelta | "P3DT12H00M00S"(3日12時間を与えた場合) |
Decimal | "123.45"(文字列) |
UUID | "550e8400-e29b-41d4-a716-446655440000" |
Promise (lazy) | str() 評価後の文字列 |
ネスト関係の扱い
旧例の注意:後半のfields=__all__/depth=1は最初の明示field例とは別のクラスです。同じファイルへ貼るとBookSerializerという名前を上書きします。depthの関連表示はread-onlyでも他のfieldを含む保存全体が禁止になるわけではなく、関連の公開fieldや所有者の制限を自動で保証しません。
# Author → Book[]
class AuthorWithBooksSerializer(serializers.ModelSerializer):
books = BookSerializer(many=True, read_only=True) # related_name='books' で逆参照
class Meta:
model = Author
fields = ['id', 'name', 'books']
# 出力
# {
# "id": 1, "name": "村上春樹",
# "books": [
# {"id": 11, "title": "...", "isbn": "..."},
# {"id": 12, "title": "...", "isbn": "..."}
# ]
# }
# depth で簡易ネスト(書き込みは不可)
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
depth = 1 # ForeignKey が自動ネスト
SerializerMethodField で計算項目
旧例の注意:この計算例も日付null/未来と業務の時刻帯を考慮していません。build_absolute_uriのHost/HTTPS/proxy設定とAPIルートは別に確認します。method fieldは認可を代行せず、追加SQLが出る場合は実際に測ります。
class BookSerializer(serializers.ModelSerializer):
days_since_published = serializers.SerializerMethodField()
author_name = serializers.CharField(source='author.name', read_only=True)
full_url = serializers.SerializerMethodField()
class Meta:
model = Book
fields = ['id', 'title', 'author_name',
'days_since_published', 'full_url']
def get_days_since_published(self, obj):
from datetime import date
return (date.today() - obj.published_at).days
def get_full_url(self, obj):
request = self.context.get('request')
return request.build_absolute_uri(f'/books/{obj.id}/') if request else None
パフォーマンス: N+1 を避ける
旧例の注意:これは概念比較の旧断片です。Prefetchのimportやis_publishedフィールド等のモデル前提が省略されています。クエリ数/公開範囲/結果の同一性を比較し、select_relatedだけで常に最速・一定メモリとは断定しません。
# ❌ N+1: author を毎回 SELECT
qs = Book.objects.all()
BookSerializer(qs, many=True).data
# SELECT * FROM book;
# SELECT * FROM author WHERE id=1; ← N 回
# SELECT * FROM author WHERE id=2;
# ...
# ✅ select_related (1:1, ForeignKey)
qs = Book.objects.select_related('author')
# ✅ prefetch_related (1:N, M:N)
qs = Author.objects.prefetch_related('books')
# ✅ さらに細かく
qs = Author.objects.prefetch_related(
Prefetch('books', queryset=Book.objects.filter(is_published=True))
)
ページネーション
旧例の注意:この全体設定だけで普通の関数ビューやapi_viewが自動ページングされるわけではありません。新例はViewSetにpagination_classを明示します。旧CursorPaginationのimport/接続も省略されており、nullable/更新される日付と同点順を検討せず高速・重複なしとは保証しません。
# settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 20,
}
# 出力
# {
# "count": 145,
# "next": "http://localhost:8000/books/?page=2",
# "previous": null,
# "results": [ ... ]
# }
# Cursor 方式(大量データ向け)
class BookCursor(CursorPagination):
ordering = '-published_at'
page_size = 50
カスタム to_dict() アプローチ
旧例の注意:このBook定義にはauthorがないためwith_author=Trueはこのままでは動きません。モデル側へto_dictを足すだけで認可・公開範囲・上限は設定されず、QuerySet全件やUserの内部フィールドを丸ごと返す解決策ではありません。
# models.py に直接生やす
class Book(models.Model):
title = models.CharField(max_length=200)
isbn = models.CharField(max_length=13)
def to_dict(self, *, with_author=False):
d = {
'id': self.id,
'title': self.title,
'isbn': self.isbn,
}
if with_author:
d['author'] = self.author.to_dict()
return d
# views.py
def book_list(request):
qs = Book.objects.select_related('author')
return JsonResponse({'results': [b.to_dict(with_author=True) for b in qs]})
FAQ
Q: JsonResponse と HttpResponse の違いは?
A: JsonResponse は内部で json.dumps(cls=DjangoJSONEncoder) を呼び、Content-Type: application/json を自動付与します。素の HttpResponse だと両方手動。
Q: 日付のタイムゾーンが UTC で返ってしまう
A: settings.py の TIME_ZONE と USE_TZ=True を確認。表示用に Asia/Tokyo へ変換するには django.utils.timezone.localtime()。
Q: DRF を入れずに JWT 認証だけ追加したい
A: ライブラリ名だけで安全性や速度の優劣は断定できません。必要な認証方式と検証・失効・保管等を別に設計します。本稿はsession認証の隔離教材で、JWTや実ログインAPIの実装は検証していません。
値の変換と公開境界の確認
model_to_dictも公開DTOではありません。教材ではprivate_noteを含む辞書となり、既定のJsonResponseへモデルやQuerySetをそのまま渡すとTypeErrorになりました。safe=Falseはリスト等のトップレベル型を許す指定で、ユーザーの閲覧権限を解除するものではありません。
DjangoJSONEncoderではdateは日付文字列、Decimal/UUIDは文字列、3日12時間のtimedeltaはP3DT12H00M00Sでした。UTCのdatetimeはZ形式で小数秒はミリ秒までとなる例を確認し、時刻帯付きtimeはValueErrorになる条件も検査しました。JSONにはdate/Decimal型がそのまま保存されるわけではなく、受信側と型・精度・null・時刻帯の契約を合わせます。
5冊を同じ応答内容で比較した隔離検体では、著者へのN+1が6 SELECT、select_relatedで1 SELECTでした。これはそのモデル/serializer/データでの本数であり、常に6→1、最速、同じメモリ使用量という保証ではありません。prefetchで取得した全関連をそのまま公開せず、関連の範囲と出力fieldも確認します。
検証範囲と関連資料
2026年10月26日確認。Python3.12.10/Django5.2.18/DRF3.18.3/SQLite3.49.1の新しい専用メモリDBで14試験を確認しました。実sessionとCSRF検査を有効にし、匿名/所有者/別人CRUD、他人author_id・入力owner等の拒否、拒否時のBook不変、公開field・不整合な関連、ページ上限、JSONの型/日付/null/未来日とN+1の同じ結果を比較しています。
本番データ/設定/依存/schemaは変更せず、本番POSTやmigrationは実行していません。実ブラウザ/TLS/CORS/Token/JWT・MySQL/PostgreSQL・並列更新・性能・全業務認可・全serializerの組合せは未検証です。ページ順を固定しても同時更新中のsnapshotは保証しません。
送信側はAjax POSTとCSRF・認可の教材、ビューの役割はViewの子ページ案内を参照してください。公式資料:Djangoのserialize/encoder、JsonResponse、DRFの入力関連queryset、認可、ページング。
子ページはありません
- 環境構築とプロジェクト/アプリの作成
- MVC(MVT)のそれぞれの使い方と説明
- データベースへの接続と操作
- Django Administration
- git管理
- エラー一覧
- バージョンの確認方法
- ログ出力方法
- SQLのログ出力方法
- ログのローテート設定
- settings.pyの定数にアクセスする方法
- 本番環境へのインストールとアプリのデプロイ(apache編)
- 本番環境へのインストールとアプリのデプロイ(nginx編)
- djangoアプリの本番の開始URLを変更する
- 静的(static)ファイルの置き場所と読み込み(画像、css、js )
- CSRFトークンをAjaxで使用する方法
- ajaxの使用例(POST編)
- ファイルのアップロードとファイルの名前
- クイックスタート/チュートリアル
- ログイン機能
- テンプレート側のログイン判定
- ビュー側のログイン判定
- 管理者ユーザーの作成/判定と管理画面
- モデルのjson化とレスポンス
- runserverでポートを指定する方法
- cronによるバッチ実行
- テンプレートで利用する共通のcontextを定義する方法
- プログラムが本番サーバーで反映されない場合の対処法
- APIの作成
- cron用コマンド・ファイルの作成
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスのソフト一覧|Blender・Metasequoiaと用途別の選び方
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Visual Studio「デザイナーを表示できません」エラーの原因と対処 2026-10-28 12:06:00
- SSH 認証に失敗しました。再試行してください の対処 2026-10-28 12:06:00
- SSH2 秘密鍵の読み込みに失敗しました の原因と対処 2026-10-28 12:06:00
- TeraTerm のよくあるエラーと対処法完全ガイド — Connection refused / 2026-10-28 12:06:00
- Visual Studio エラー一覧|コンパイルエラー・警告の確認方法と対処 2026-10-28 11:39:57
- Whitelabel Error Page の原因と消し方|Spring Boot のエラーページ 2026-10-28 11:39:57
- Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法 2026-10-28 11:39:57
- SQL WHERE 句完全ガイド 2026-10-28 11:39:57
- SQL JOIN 完全ガイド (INNER/LEFT/RIGHT/FULL OUTER) 2026-10-28 11:39:57
- tomcat の起動 / 停止ログと catalina.log・catalina.out の違い 2026-10-28 10:24:23
- Tomcat の起動確認方法 5 つ|localhost:8080・ポート・プロセス・ログ 2026-10-28 10:24:23
- Oracle 19c COMMITの使い方: 暗黙コミット・自動確定・応答不明時の確認 2026-10-28 09:59:09
- Oracle 19c DELETE文|削除対象の確認・COMMIT前の判断・ROLLBACKの条件 2026-10-28 09:59:09
- Oracle 19c INSERT文|INSERT ALL・SELECT・RETURNINGとMERGEの使い分け 2026-10-28 09:59:09
- Oracle 19cのトランザクション制御|COMMIT・ROLLBACK・分離レベルと接続設定 2026-10-28 09:59:09