๊ฐ์
์ด ๊ธ์ ํํ๋์ ๋ธ๋ก๊ทธ ๊ฒ์๊ธ์์ ์๊ฐ์ ๋ฐ์ ์์ฑํ๊ฒ ๋์์ต๋๋ค.
์ฐ๋ฆฌ๋ ์คํ๋ง ํ๋ ์์ํฌ๋ฅผ ํตํด RDBMS๋ฅผ ํ์ฉํ๋ ๊ณผ์ ์์, ์ฐ๋ฆฌ๋ ์ฑ๋ฅ ์ต์ ํ, ๊ฐ๋ ์ฑ ํฅ์, ๋ฐ์ดํฐ ์ผ๊ด์ฑ ์ ์ง ๋ฑ ์ฌ๋ฌ ์ด์ ๋ก ๋น์ฆ๋์ค ๋ก์ง์ @Transactional(readOnly=true) ์ด๋ ธํ ์ด์ ์ ์์ฃผ ์ฌ์ฉํ๊ณค ํฉ๋๋ค. ๊ทธ๋ฐ๋ฐ ์ด ์ด๋ ธํ ์ด์ ์ ์ด๋ ํ ์๋ฆฌ๋ก ๋์ํ๋ ๊ฒ์ผ๊น์? ์ด๋ฒ ๊ธ์์๋ @Transactional(readOnly=true)์ JDBC ๋จ๊ณ์์์ ๋์ ๊ณผ์ ์ ์์ฃผ๋ก ์ดํด๋ณด๋ ค ํฉ๋๋ค.
๋์ ๊ณผ์
๋น์ฆ๋์ค ๋ก์ง์ @Transactional(readOnly=true)์ ๊ฑธ๊ณ ์คํํ๋ ๊ฒฝ์ฐ ๋์ํ๋ ์ ์ฒด์ ์ธ ๊ณผ์ ์ ์๋์ ๊ฐ์ต๋๋ค.
- ํธ๋์ญ์ ์์
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์ค๋น
- ์ฝ๊ธฐ ์ ์ฉ ์ํ ์ ํ
- ๋น์ฆ๋์ค ๋ก์ง ์คํ
- ํธ๋์ญ์ ์ข ๋ฃ
๊ฐ ๊ณผ์ ์ ๋ํด ์์ธํ๊ฒ ํ๋ฒ ์์๋ณด๊ฒ ์ต๋๋ค.
1. ํธ๋์ญ์ ์์
์๋์ ๊ฐ์ด @Transactional(readOnly=true)๊ฐ ์ค์ ๋ ๋น์ฆ๋์ค ๋ก์ง์ ํธ์ถํ๋ฉด ํธ๋์ญ์ ์ด ์์๋ฉ๋๋ค.
@Service public class MyService { @Transactional(readOnly=true) public MyData getData(int id) { // ๋น์ฆ๋์ค ๋ก์ง } }
์ ๋ฉ์๋๊ฐ ํธ์ถ๋๋ฉด ์คํ๋ง์ AOP ํ๋ ์์ํฌ๊ฐ ์ด๋ฅผ ์ธ์งํ๊ณ , ํธ๋์ญ์ ์ธํฐ์ ํฐ๋ฅผ ํตํด ํธ๋์ญ์ ์ ์์ํฉ๋๋ค.
์คํ๋ง์ ํธ๋์ญ์ ๊ด๋ฆฌ๋ AOP(Aspect-Oriented Programming) ๊ธฐ๋ฐ์ผ๋ก ์๋ํ๋ฉฐ, ์ด๋ฅผ ํตํด ๋น์ฆ๋์ค ๋ก์ง๊ณผ ํธ๋์ญ์ ์ฒ๋ฆฌ๋ฅผ ๋ถ๋ฆฌํ์ฌ ์ฝ๋์ ๊ฐ๋ ์ฑ๊ณผ ์ฌ์ฌ์ฉ์ฑ์ ํฅ์์ํค๋ ํจ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค. ์ด ๊ณผ์ ์์ ํธ๋์ญ์ ์ธํฐ์ ํฐ๋ ์ค์ถ์ ์ธ ์ญํ ์ ๋ด๋นํ๋ฉฐ, ํธ๋์ญ์ ์ ์์, ์ข ๋ฃ, ํ์์ ๋กค๋ฐฑ ๋ฑ์ ์์ ์ ์ํํฉ๋๋ค.
@Transactional(readOnly=true) ์ด๋
ธํ
์ด์
์ ํตํด getData ๋ฉ์๋๊ฐ ํธ์ถ๋ ๋, ํธ๋์ญ์
์ธํฐ์
ํฐ๊ฐ ํ์ฑํ๋์ด ์๋ก์ด ํธ๋์ญ์
์ ์์ํฉ๋๋ค. ์ด๋ ํธ๋์ญ์
์ ์์ฑ๋ค(์ฝ๊ธฐ ์ ์ฉ, ๊ฒฉ๋ฆฌ ์์ค, ํ์์์, ์ ํ ๋ฐฉ์ ๋ฑ)์ด ํธ๋์ญ์
๋งค๋์ ์๊ฒ ์ ๋ฌ๋ฉ๋๋ค.
2. ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์ค๋น

ํธ๋์ญ์ ์ด ์์๋๋ฉด ์คํ๋ง์ ํธ๋์ญ์ ๊ด๋ฆฌ์๋ DataSourceTransactionalManager.doBegin ๋ฉ์๋ ๋ด๋ถ์์ DataSourceUtils.prepareConnectionForTransaction ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ ์ค๋นํฉ๋๋ค. ์ด ๋ฉ์๋๋ ์คํ๋ง ํ๋ ์์ํฌ์์ ์ ๊ณตํ๋ ๋ฉ์๋๋ก ํธ๋์ญ์ ์ ์๋ฅผ ๋ฐ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ ํ๋ณดํ๊ณ , ํด๋น ์ฐ๊ฒฐ์ ํธ๋์ญ์ ์ ์์ฑ๋ค์ ์ ์ฉํ๋ ์ญํ ์ ํฉ๋๋ค.
// DataSourceUtils.java public static Integer prepareConnectionForTransaction(Connection con, TransactionDefinition definition) throws SQLException { Assert.notNull(con, "No Connection specified"); if (definition.isReadOnly()) { try { if (logger.isDebugEnabled()) { logger.debug("Setting JDBC Connection [" + con + "] read-only"); } con.setReadOnly(true); } catch (SQLException | RuntimeException ex) { // ์์ธ ์ฒ๋ฆฌ } } // ๊ฒฉ๋ฆฌ ์์ค ์ค์ ๋ฑ์ ์ถ๊ฐ ์ฝ๋ }

DataSourceUtils์ prepareConnectionForTransaction ๋ฉ์๋ ๋ด์์ definition.isReadOnly()๋ @Transactional(readOnly=true) ์ด๋ ธํ ์ด์ ์ ๊ฐ์ด true์ธ์ง ํ์ธํ๋ ๋ถ๋ถ์ ๋๋ค. ์ด ๊ฐ์ด true์ผ ๊ฒฝ์ฐ, con.setReadOnly(true)๊ฐ ํธ์ถ๋์ด ํด๋น ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ด ์ฝ๊ธฐ ์ ์ฉ ๋ชจ๋๋ก ์ค์ ๋ฉ๋๋ค. ์ด ์ค์ ์ ๋ฐ๋ผ ํด๋น ์ฐ๊ฒฐ์ ํตํด ์ํ๋๋ ๋ชจ๋ SQL ๋ช ๋ น์ ๋ฐ์ดํฐ ๋ณ๊ฒฝ ์์ด ์ฝ๊ธฐ ์ ์ฉ ๋ชจ๋๋ก ๋์ํ๊ฒ ๋ฉ๋๋ค.
๋ํ ์ด ๋ฉ์๋๋ ํธ๋์ญ์ ์ ์์ ๋ฐ๋ผ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ ๊ฒฉ๋ฆฌ ์์ค์ ์ค์ ํ๋ ๋ถ๋ถ๋ ํฌํจํ๊ณ ์์ด, ํธ๋์ญ์ ์ ๊ฒฉ๋ฆฌ ์์ค์ด ์ ์๋์ด ์๋ค๋ฉด, ํด๋น ๊ฒฉ๋ฆฌ ์์ค์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ ์ ์ฉ๋ฉ๋๋ค.
์ด๋ ๊ฒ ๋ชจ๋ ๊ณผ์ ์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋๋ฉด, ํธ๋์ญ์
์ ์ํ ์ค๋น๊ฐ ๋ชจ๋ ๋ง๋ฌด๋ฆฌ๋ ์ํ์
๋๋ค. ์ดํ์ ์ฒ๋ฆฌ๋ ์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ ํตํด ์ด๋ฃจ์ด์ง๋ฉฐ, ํธ๋์ญ์
์ด ์ข
๋ฃ๋ ๋๊น์ง ์ด ์ฐ๊ฒฐ์ ์ ์ง๋ฉ๋๋ค. ํธ๋์ญ์
์ด ์ข
๋ฃ๋ ํ์๋ resetConnectAfterTransaction ๋ฉ์๋๋ฅผ ํตํด ์ฐ๊ฒฐ ์ํ๊ฐ ์๋๋๋ก ๋ณต์๋ฉ๋๋ค.
3. ์ฝ๊ธฐ ์ ์ฉ ์ํ ์ ํ
์ฝ๊ธฐ ์ ์ฉ์ผ๋ก ์ค์ ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ MySQL์ JDBC ๋๋ผ์ด๋ฒ์ ์ ๋ฌ๋๋ฉฐ JDBC ๋๋ผ์ด๋ฒ๋ Connection.setReadOnly(true) ํธ์ถ์ ์ธ์งํ๊ณ , ๋ด๋ถ์ ์ผ๋ก ConnectionImpl.setReadOnlyInternal ๋ฉ์๋๋ฅผ ์คํํฉ๋๋ค.
ConnectionImpl.setReadOnlyInternal ๋ฉ์๋๋ MySQL์ JDBC ๋๋ผ์ด๋ฒ์์ ์ ๊ณตํ๋ ๋ฉ์๋๋ก, ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ ์ฝ๊ธฐ ์ ์ฉ ์ํ๋ฅผ ์ค์ ํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ์ด ๋ฉ์๋๋ MySQL ์๋ฒ์ ๋ฒ์ ์ ํ์ธํ ํ, ์ฝ๊ธฐ ์ ์ฉ ์ํ๋ฅผ MySQL ์๋ฒ์ ์ ํํ๋ ค๊ณ ์๋ํฉ๋๋ค.
// ConnectionImpl.java @Override public void setReadOnlyInternal(boolean readOnlyFlag) throws SQLException { synchronized (getConnectionMutex()) { // note this this is safe even inside a transaction if (this.readOnlyPropagatesToServer.getValue() && versionMeetsMinimum(5, 6, 5)) { if (!this.useLocalSessionState.getValue() || readOnlyFlag != this.readOnly) { this.session.execSQL(null, "set session transaction " + (readOnlyFlag ? "read only" : "read write"), -1, null, false, this.nullStatementResultSetFactory, null, false); } } this.readOnly = readOnlyFlag; } }

์ ์ฝ๋์์ versionMeetsMinimum(5, 6, 5)๋ MySQL ์๋ฒ์ ๋ฒ์ ์ด 5.6.5 ์ด์์ธ์ง ํ์ธํ๋ ๋ถ๋ถ์ ๋๋ค. ๋ง์ฝ 5.6.5 ๋ฒ์ ์ด์์ผ ๊ฒฝ์ฐ execSQL(..., "set session transaction read only", ...)๊ฐ ํธ์ถ๋์ด, ์ฝ๊ธฐ ์ ์ฉ ์ํ๋ฅผ MySQL ์๋ฒ์ ์ ๋ฌํ๋ SQL ๋ช ๋ น์ด ์คํ๋ฉ๋๋ค.
์ด ๊ณผ์ ์ ํตํด JDBC ๋๋ผ์ด๋ฒ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ ์ฝ๊ธฐ ์ ์ฉ ์ํ๋ฅผ MySQL ์๋ฒ์ ์ ํํฉ๋๋ค. ์ด ๊ณผ์ ์ JDBC ๋๋ผ์ด๋ฒ์ MySQL ์๋ฒ ๊ฐ์ ํต์ ๊ณผ์ ์์ ์ด๋ฃจ์ด์ง๋ฉฐ, ์ด๋ฅผ ํตํด MySQL ์๋ฒ๋ ํด๋น ์ฐ๊ฒฐ์ด ์ฝ๊ธฐ ์ ์ฉ์์ ์ธ์งํ๊ฒ ๋ฉ๋๋ค.
์ฌ๊ธฐ์ ๋ง์ฝ MySQL ์๋ฒ์ ๋ฒ์ ์ด 5.6.5 ๋ฏธ๋ง์ด๋ผ๋ฉด, 'READ ONLY'์ 'READ WRITE' ํธ๋์ญ์ ํน์ฑ์ด ์ง์๋์ง ์์ ์กฐ๊ฑด๋ฌธ์ ํต๊ณผํ์ง ๋ชปํด ์ฝ๊ธฐ ์ ์ฉ ์ํ๊ฐ MySQL ์๋ฒ์ ์ ํ๋์ง ์์ต๋๋ค.
์๋ฒ ๋ฒ์ ์ด 5.6.5 ๋ฏธ๋ง์ธ ๊ฒฝ์ฐ, 'READ ONLY'์ 'READ WRITE' ํธ๋์ญ์ ํน์ฑ์ด ์ง์๋์ง ์๋๋ค.
MySQL 5.6.5 ์ด์ ๋ฒ์ ์์๋ ์ธ์ ๋ ๋ฒจ์์๋ง ์ฝ๊ธฐ ์ ์ฉ ์ํ๋ฅผ ์ค์ ํ๋ ๊ฒ์ด ๊ฐ๋ฅํ์ต๋๋ค. ํ์ง๋ง, ํธ๋์ญ์ ์์ค์์ 'READ ONLY'์ 'READ WRITE' ํน์ฑ์ ์ง์ ํ๋ ๊ธฐ๋ฅ์ MySQL 5.6.5 ๋ฒ์ ๋ถํฐ ์ ๊ณต๋์์ต๋๋ค.(https://forums.mysql.com/read.php?3,524924)
์ธ์ ๋ ๋ฒจ์์์ ์ฝ๊ธฐ ์ ์ฉ ์ํ์ ํธ๋์ญ์ ์์ค์์์ ์ฝ๊ธฐ ์ ์ฉ ์ํ๋ ๋ค์๊ณผ ๊ฐ์ ์ฐจ์ด์ ์ด ์์ต๋๋ค.
- ์ธ์ ๋ ๋ฒจ์์์ ์ฝ๊ธฐ ์ ์ฉ ์ํ: ์ธ์ ๋ ๋ฒจ์์ ์ฝ๊ธฐ ์ ์ฉ ์ํ๋ฅผ ์ค์ ํ๋ฉด, ํด๋น ์ธ์ ์์ ์ํ๋๋ ๋ชจ๋ ํธ๋์ญ์ ์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฝ๊ธฐ ์ ์ฉ์ผ๋ก ๋์ํฉ๋๋ค. ์ฆ, ์ธ์ ๋ด์ ๋ชจ๋ ํธ๋์ญ์ ์์ ๋ฐ์ดํฐ ๋ณ๊ฒฝ ์์ ์ ๊ฑฐ๋ถ๋๊ฑฐ๋ ๋ฌด์๋ฉ๋๋ค. ์ด ์ค์ ์ ํด๋น ์ธ์ ๋ด์ ๋ชจ๋ ํธ๋์ญ์ ์ ์ ์ฉ๋๋ฉฐ, ์ธ์ ์ด ์ข ๋ฃ๋๊ฑฐ๋ ๋ช ์์ ์ผ๋ก ๋ณ๊ฒฝ๋๊ธฐ ์ ๊น์ง ์ ์ง๋ฉ๋๋ค.
- ํธ๋์ญ์ ์์ค์์์ ์ฝ๊ธฐ ์ ์ฉ ์ํ: ํธ๋์ญ์ ์์ค์์ ์ฝ๊ธฐ ์ ์ฉ ์ํ๋ฅผ ์ค์ ํ๋ฉด, ํด๋น ์ค์ ์ ์ค์ง ๊ทธ ํธ๋์ญ์ ์๋ง ์ ์ฉ๋ฉ๋๋ค. ์ฆ ํด๋น ํธ๋์ญ์ ์ด ์ข ๋ฃ๋๋ฉด, ์ด ์ค์ ์ ํด์ ๋๋ฉฐ ๋ค์ ํธ๋์ญ์ ์ ์ธ์ ๋ ๋ฒจ์ ์ค์ ์ ๋ฐ๋ฅด๊ฒ ๋ฉ๋๋ค. ์ด ์ค์ ์ ํธ๋์ญ์ ์ ์์๊ณผ ์ข ๋ฃ ์ฌ์ด์๋ง ์ ํจํ๋ฉฐ, ํธ๋์ญ์ ์ ๋ฒ์๋ฅผ ๋ฒ์ด๋๋ ์ํฅ์ ์์ต๋๋ค.
์ฝ๋๋ฅผ ๋ณด๋ฉด "set session transaction " + (readOnlyFlag ? "read only" : "read write") ๋ถ๋ถ์ MySQL ์๋ฒ์ ์ ๋ฌ๋๋ ๋ช ๋ น์ด๋ก, 5.6.5 ์ด์ ๋ฒ์ ์์๋ ํด๋น ๋ช ๋ น์ด๋ฅผ ์ง์ ์ ์ผ๋ก ์ง์ํ์ง ์์ต๋๋ค. ๋ฐ๋ผ์, MySQL ์๋ฒ์ ๋ฒ์ ์ด 5.6.5 ๋ฏธ๋ง์ผ ๊ฒฝ์ฐ์๋ JDBC ๋๋ผ์ด๋ฒ๊ฐ 'READ ONLY' ๋๋ 'READ WRITE' ํธ๋์ญ์ ํน์ฑ์ ์๋ฒ์ ์ ๋ฌํ ์ ์์ต๋๋ค.
ํ์ง๋ง MySQL ์๋ฒ์ ๋ฒ์ ์ด 5.6.5 ๋ฏธ๋ง์ธ ๊ฒฝ์ฐ์๋, ์ฝ๋ ๋ง์ง๋ง์ this.readOnly = readOnlyFlag๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ ์ฝ๊ธฐ ์ ์ฉ์ผ๋ก ์ค์ ํ๋๋ก JDBC ๋๋ผ์ด๋ฒ์๊ฒ ์ง์ํ๊ฒ ๋ฉ๋๋ค.
๊ฒฐ๊ณผ์ ์ผ๋ก JDBC ๋๋ผ์ด๋ฒ๋ ์ด ์ฐ๊ฒฐ์ ํตํด ๋ค์ด์ค๋ ๋ชจ๋ ์ฟผ๋ฆฌ๋ฅผ ์ฝ๊ธฐ ์ ์ฉ์ผ๋ก ์ทจ๊ธํ๋ฉฐ, ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝํ๋ ์ฟผ๋ฆฌ๊ฐ ์คํ๋๋ ค๊ณ ํ๋ฉด JDBC ๋๋ผ์ด๋ฒ๊ฐ ์ด๋ฅผ ๊ฑฐ๋ถํ๊ณ ์ค๋ฅ๋ฅผ ๋ฐํํฉ๋๋ค. ์ด๋ก ์ธํด MySQL ์๋ฒ์ ๋ฒ์ ์ ์๊ด์์ด ์ฝ๊ธฐ ์ ์ฉ ํธ๋์ญ์ ์ ์์ ์ฑ์ ๋ณด์ฅ๋ ์ ์์ต๋๋ค.

๊ทธ ํ DataSourceTransactionManager ํด๋์ค์ doBegin() ๋ฉ์๋ ๋ด์์ DataSourceTransactionManager.prepareTransactionalConnection() ๋ฉ์๋๊ฐ ํธ์ถ๋ฉ๋๋ค. ์ด ๋ฉ์๋๋ ํธ๋์ญ์ ์์ค์์ ์ฝ๊ธฐ ์ ์ฉ ๋ชจ๋๋ฅผ ๊ฐ์ ํ๊ธฐ ์ํ ๊ฒ์ ๋๋ค. ์ด๋ฏธ DataSourceUtils.prepareConnectionForTransaction(con, definition) ํธ์ถ์ ์ํด ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ด ์ฝ๊ธฐ ์ ์ฉ์ผ๋ก ์ค์ ๋์์ง๋ง, ์ด๋ ์ฐ๊ฒฐ ์์ค์ ์ค์ ์ด๋ฏ๋ก ์ดํ์ ๊ฐ์ ์ฐ๊ฒฐ์ ๋ค๋ฅธ ํธ๋์ญ์ ์์ ์ฌ์ฌ์ฉํ ๊ฒฝ์ฐ์ ์ฝ๊ธฐ ์ ์ฉ ์ค์ ์ด ๋ณ๊ฒฝ๋ ์ ์์ต๋๋ค.
ํ์ง๋ง ๊ธฐ๋ณธ ์ค์ ์์์ DataSourceTransactionManager.prepareTransactionalConnection() ๋ฉ์๋๊ฐ ์ค์ ๋ก ์ํ๋ ๊ฐ๋ฅ์ฑ์ ๊ฑฐ์ ์์ต๋๋ค. isEnforceReadOnly()์ ๊ธฐ๋ณธ๊ฐ์ด false์ด๊ณ , enforceReadOnly ์์ฑ์ DataSourceTransactionManager์ ์ค์ ์ผ๋ก์จ @Transactional ์ด๋ ธํ ์ด์ ์ readOnly ์์ฑ๊ณผ๋ ๋ณ๊ฐ์ด๊ธฐ ๋๋ฌธ์ ๋๋ค.
๋ฐ๋ผ์ enforceReadOnly๋ฅผ true๋ก ์ค์ ํ๋ ค๋ฉด, DataSourceTransactionManager์ ์ธ์คํด์ค๋ฅผ ์์ฑํ๊ฑฐ๋ ๊ตฌ์ฑํ๋ ๊ณผ์ ์์ ๋ช ์์ ์ผ๋ก ์ค์ ํด์ผ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ์๋์ ๊ฐ์ด ์ค์ ํ ์ ์์ต๋๋ค.
@Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { DataSourceTransactionManager txManager = new DataSourceTransactionManager(); txManager.setDataSource(dataSource); txManager.setEnforceReadOnly(true); // ์ฝ๊ธฐ ์ ์ฉ ํธ๋์ญ์
๊ฐ์ ์ค์ return txManager; }
์ง๊ธ๊น์ง์ ๊ณผ์ ์ ์ ๋ฆฌํ๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- DataSourceTransactionManager์ doBegin() ๋ฉ์๋๊ฐ ํธ๋์ญ์ ์ ์์ํ๋ ๊ณผ์ ์ ๋ด๋นํ๋ค.
- doBegin() ๋ฉ์๋ ๋ด๋ถ์์ DataSourceUtils.prepareConnectionForTransaction(con, definition)์ด ํธ์ถ๋๋๋ฐ, ์ด ํจ์์์๋ ํธ๋์ญ์ ์ ์์ ๋ฐ๋ผ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ ์ค๋นํ๋ค.
- ์ด ๊ณผ์ ์์ ConnectionImpl์ setReadOnlyInternal() ๋ฉ์๋๊ฐ ํธ์ถ๋๋ฉฐ, ์ด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ ์ฝ๊ธฐ ์ ์ฉ ์ํ๋ก ์ค์ ํ๋ค.
- ๋ง์ง๋ง์ผ๋ก, DataSourceTransactionManager์ doBegin() ๋ฉ์๋ ๋ด์์ prepareTransactionalConnection()์ด ํธ์ถ๋์ด, ํธ๋์ญ์ ์ ์ํ ์ต์ข ์ ์ธ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์ค๋น๋ฅผ ์๋ฃํ๋ค.
4. ๋น์ฆ๋์ค ๋ก์ง ์คํ
๋น์ฆ๋์ค ๋ก์ง์ด ์คํ๋๋ ์ด ๋จ๊ณ์์๋ ์ ํ๋ฆฌ์ผ์ด์ ๋ก์ง์ ๋ฐ๋ผ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฟผ๋ฆฌ๋ฅผ ์ํํ๊ฒ ๋ฉ๋๋ค. ์ด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ด ์ฝ๊ธฐ ์ ์ฉ ๋ชจ๋๋ก ์ค์ ๋์ด ์๋ค๋ฉด, ๋ฐ์ดํฐ ๋ณ๊ฒฝ(INSERT, UPDATE, DELETE ๋ฑ)์ ์๋ํ๋ SQL ๋ช ๋ น์ด ์คํ๋๋ฉด SQLException์ด ๋ฐ์ํฉ๋๋ค. ์ด๋ฌํ ๊ฒ์ฆ ๊ณผ์ ์ JDBC ๋๋ผ์ด๋ฒ๊ฐ SQL ๋ช ๋ น ์คํ ์ ์ ํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ ์ํ๋ฅผ ํ์ธํ์ฌ ์ด๋ฃจ์ด์ง๋๋ค.
MySQL 5.6.5 ์ด์
MySQL 5.6.5 ์ด์์์๋ JDBC ๋๋ผ์ด๋ฒ์ MySQL ์๋ฒ ๋ชจ๋์์ 'READ ONLY' ํธ๋์ญ์ ์ ๊ด๋ฆฌํฉ๋๋ค. ์ด๋์ ๋์ ๊ณผ์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- JDBC ๋๋ผ์ด๋ฒ ์ฐจ์์ ๊ฒ์ฆ: ์ ํ๋ฆฌ์ผ์ด์ ์ด SQL ๋ช ๋ น์ ์คํํ๋ ค๊ณ ํ ๋, JDBC ๋๋ผ์ด๋ฒ๋ ๋จผ์ ์ฐ๊ฒฐ์ ์ํ๋ฅผ ํ์ธํฉ๋๋ค. ๋ง์ฝ ์ฐ๊ฒฐ์ด ์ฝ๊ธฐ ์ ์ฉ ๋ชจ๋๋ก ์ค์ ๋์ด ์๋ค๋ฉด, JDBC ๋๋ผ์ด๋ฒ๋ ๋ฐ์ดํฐ ๋ณ๊ฒฝ์ ์๋ํ๋ SQL ๋ช ๋ น์ ๊ฑฐ๋ถํ๊ณ SQLException์ ๋ฐ์์ํต๋๋ค.
- MySQL ์๋ฒ ์ฐจ์์ ๊ฒ์ฆ: ๋ง์ฝ JDBC ๋๋ผ์ด๋ฒ ์ฐจ์์์ SQL ๋ช ๋ น์ด ๊ฑฐ๋ถ๋์ง ์์๋ค๋ฉด, SQL ๋ช ๋ น์ MySQL ์๋ฒ๋ก ์ ๋ฌ๋ฉ๋๋ค. MySQL ์๋ฒ๋ 'READ ONLY' ํธ๋์ญ์ ์ค์ ์ ์ธ์ํ๊ณ , ๋ฐ์ดํฐ ๋ณ๊ฒฝ์ ์๋ํ๋ SQL ๋ช ๋ น์ ์ฐจ๋จํ๊ณ ์ค๋ฅ๋ฅผ ๋ฐํํฉ๋๋ค.
MySQL 5.6.5 ๋ฏธ๋ง
MySQL 5.6.5 ๋ฏธ๋ง์์๋ 'READ ONLY'์ 'READ WRITE' ํธ๋์ญ์
ํน์ฑ์ด ์๋ฒ ์ฐจ์์์ ์ง์๋์ง ์์ต๋๋ค. ์ด ๊ฒฝ์ฐ ๊ฒ์ฆ ๊ณผ์ ์ JDBC ๋๋ผ์ด๋ฒ๊ฐ ์ ์ ์ผ๋ก ๋ด๋นํฉ๋๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก JDBC ๋๋ผ์ด๋ฒ๋ ๋จผ์ ์ฐ๊ฒฐ์ ์ํ๋ฅผ ํ์ธํ๊ณ , ์ฐ๊ฒฐ์ด ์ฝ๊ธฐ ์ ์ฉ ๋ชจ๋๋ก ์ค์ ๋์ด ์๋๋ฐ ๋ฐ์ดํฐ ๋ณ๊ฒฝ์ ์๋ํ๋ SQL ๋ช
๋ น์ด ๋ค์ด์จ๋ค๋ฉด SQLException์ ๋ฐ์์ํต๋๋ค.
5. ํธ๋์ญ์ ์ข ๋ฃ
ํธ๋์ญ์ ์ข ๋ฃ ๋จ๊ณ๋ ๋น์ฆ๋์ค ๋ก์ง ์คํ์ด ์๋ฃ๋ ํ์ ์ด๋ฃจ์ด์ง๋ฉฐ, ์ด ๋จ๊ณ์์ ์ปค๋ฐ ํน์ ๋กค๋ฐฑ์ด ์ผ์ด๋๊ฒ ๋ฉ๋๋ค.
์ ๋ฆฌ
์ฝ๊ธฐ ์ ์ฉ ํธ๋์ญ์ ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ ์์ ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ์ ์ ์งํ๋ฉฐ ์ฑ๋ฅ์ ํฅ์์ํค๋ ์ค์ํ ๋๊ตฌ์ ๋๋ค. ํนํ ๋ฐ์ดํฐ๋ฅผ ์ฝ๋ ์์ ์ด ์ฃผ๋ฅผ ์ด๋ฃจ๋ ํ๊ฒฝ์์๋ ์ฝ๊ธฐ ์ ์ฉ ํธ๋์ญ์ ์ ํ์ฉ์ด ํฐ ์ด์ ์ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.
์ฝ๊ธฐ ์ ์ฉ ํธ๋์ญ์ ์ ์ค์ , ๋น์ฆ๋์ค ๋ก์ง์ ์คํ, ๊ทธ๋ฆฌ๊ณ ํธ๋์ญ์ ์ ์ข ๋ฃ์ ์ธ ๋จ๊ณ๋ฅผ ๊ฑฐ์น๋ฉฐ ์ด ๊ณผ์ ์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ ์ํ๋ฅผ ํ์ธํ๊ณ , ํ์์ ๋ฐ๋ผ ์ปค๋ฐ ํน์ ๋กค๋ฐฑ์ ์ํํ๊ฒ ๋ฉ๋๋ค. MySQL 5.6.5 ์ด์๊ณผ ๋ฏธ๋ง์ ๋ฒ์ ์์๋ 'READ ONLY' ํธ๋์ญ์ ์ ๊ด๋ฆฌ ๋ฐฉ์์ด ์ฝ๊ฐ ๋ค๋ฅด์ง๋ง ํต์ฌ์ ์ธ ๋ถ๋ถ์ ๋์ผํฉ๋๋ค. ์ฆ ์ด๋ ๋ฒ์ ์์๋ ์ฝ๊ธฐ ์ ์ฉ ๋ชจ๋๋ก ์ค์ ๋ ์ฐ๊ฒฐ์์ ๋ฐ์ดํฐ ๋ณ๊ฒฝ์ ์๋ํ๋ฉด SQLException์ด ๋ฐ์ํฉ๋๋ค.
java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed
๋๊ธ