MySQL λ²μ μ λ°λ₯Έ @Transactional(readOnly=true)μ λμ κ³Όμ
κ°μ
μ΄ κΈμ ννλμ λΈλ‘κ·Έ κ²μκΈμμ μκ°μ λ°μ μμ±νκ² λμμ΅λλ€.
μ°λ¦¬λ μ€νλ§ νλ μμν¬λ₯Ό ν΅ν΄ 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