#!/usr/bin/env bash # Isolation and read-only: honoured where the transaction starts, ignored where it joins. set -euo pipefail set +m cd "$(dirname "$0")/.." source scripts/env.sh { echo "== isolation and readOnly ==" echo start_app > /dev/null curl -s "http://127.0.0.1:${APP_PORT}/tx/isolation" | python3 -c ' import json,sys d=json.load(sys.stdin) def show(label, s): print(" %-46s active=%-5s readOnly=%-5s isolation=%s" % ( label, s["actualTransactionActive"], s["readOnly"], s["isolationLevel"])) show("@Transactional(readOnly = true)", d["readOnlyScope"]) print() show("@Transactional(isolation = SERIALIZABLE) [outer]", d["serializableOuter"]["outer"]) show(" REQUIRED inner joining it", d["serializableOuter"]["inner"]) print() show("plain @Transactional [outer]", d["participantDeclaringReadUncommitted"]["outer"]) show(" inner declaring READ_UNCOMMITTED", d["participantDeclaringReadUncommitted"]["inner"])' echo echo "The last pair is the point. The inner method declares" echo "@Transactional(isolation = READ_UNCOMMITTED) and gets ISOLATION_DEFAULT, because it" echo "joined an existing physical transaction whose isolation was fixed when it began." echo "The declaration is not rejected and nothing is logged -- it is simply ignored." echo echo "Set validateExistingTransaction=true on the transaction manager and this becomes an" echo "exception instead of a silent no-op. It is off by default." echo echo "The same applies to readOnly and timeout on a participating scope." echo echo "== the transaction manager's own log lines ==" echo grep -E "Creating new transaction|Participating in existing" "$LOG" | tidy | head -12 echo echo "Note ISOLATION_SERIALIZABLE appears on the 'Creating new transaction' line and never" echo "on a 'Participating' one: participation carries no settings of its own." stop_app } > docs/output/05-isolation.txt 2>&1 cat docs/output/05-isolation.txt