[컴][웹] Spring 에서 MySql iBatis 사용




SelectStatement(MappedStatement).executeQueryWithCallback{
    ...
    String sqlString = sql.getSql(statementScope, parameterObject);
    ...
}



SelectStatement(MappedStatement).executeQueryWithCallback(StatementScope, Connection, Object, Object, RowHandler, int, int) line: 161
SelectStatement(MappedStatement).executeQueryForList(StatementScope, Transaction, Object, int, int) line: 138
SqlMapExecutorDelegate.queryForList(SessionScope, String, Object, int, int) line: 556
SqlMapExecutorDelegate.queryForList(SessionScope, String, Object) line: 541
SqlMapSessionImpl.queryForList(String, Object) line: 118  
SqlMapClientTemplate$3.doInSqlMapClient(SqlMapExecutor) line: 298
SqlMapClientTemplate.execute(SqlMapClientCallback) line: 209  
SqlMapClientTemplate.executeWithListResult(SqlMapClientCallback) line: 249
SqlMapClientTemplate.queryForList(String, Object) line: 296
CdnStatDaoiBatis.getProductTrafficTop5List(List<Map<String,Integer>>) line: 51


delete 호출시

getSqlMapClientTemplate().delete("removeData", param);
내부적으로는 update 를 호출한다.



// SqlMapClientTemplate.java
public int delete(final String statementName, final Object parameterObject)
   throws DataAccessException {

  Integer result = (Integer) execute(new SqlMapClientCallback() {
      public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
          return new Integer(executor.delete(statementName, parameterObject));
      }
  });
  return result.intValue();
});

// SqlMapClientTemplate.java
public Object execute(SqlMapClientCallback action) throws DataAccessException {
    ...
    try{
      return action.doInSqlMapClient(session);
    } ...
    finally {
        try {
            if (springCon != null) {
                if (transactionAware) {
                    springCon.close();
                }
                else {
                    DataSourceUtils.doReleaseConnection(springCon, dataSource);
                }
            }
        }
        catch (Throwable ex) {
            logger.debug("Could not close JDBC Connection", ex);
        }
    }
    ...
    finally{
        ...
        if (ibatisCon == null) {
            session.close();
        }
        

// SqlMapSessionImpl.java
public int delete(String id, Object param) throws SQLException {
    return delegate.delete(sessionScope, id, param);
}

// SqlMapExecutorDelegate.java
public int delete(SessionScope sessionScope, String id, Object param) throws SQLException {
    return update(sessionScope, id, param);
}

// SqlMapExecutorDelegate.java
public int update(SessionScope sessionScope, String id, Object param) throws SQLException {
    ...
    Transaction trans = getTransaction(sessionScope);
    boolean autoStart = trans == null;
    try {
      trans = autoStartTransaction(sessionScope, autoStart, trans);
      ...
      try {
        rows = ms.executeUpdate(statementScope, trans, param);
        ...
      }
      autoCommitTransaction(sessionScope, autoStart);


// MappedStatement.java
public int executeUpdate(StatementScope statementScope, Transaction trans, Object parameterObject) throws SQLException {
    ...
    statementScope.getSession().setCommitRequired(true);
    try {
      parameterObject = validateParameter(parameterObject);
      Sql sql = getSql();
      ...
      String sqlString = sql.getSql(statementScope, parameterObject);
      ...
      rows = sqlExecuteUpdate(statementScope, trans.getConnection(), sqlString, parameters);



// MappedStatement.java
public Sql getSql() {
    return sql;
  }


// MappedStatement.java
protected int sqlExecuteUpdate(StatementScope statementScope, Connection conn, String sqlString, Object[] parameters) throws SQLException {
    if (statementScope.getSession().isInBatch()) {
      ...
    } else {
      return getSqlExecutor().executeUpdate(statementScope, conn, sqlString, parameters);


// SqlExecutor.java
public int executeUpdate(StatementScope statementScope, Connection conn, String sql, Object[] parameters) throws SQLException {
    ...
    try {
      ...
      ps = prepareStatement(statementScope.getSession(), conn, sql);
      ...
      setStatementTimeout(statementScope.getStatement(), ps);
      ...
      statementScope.getParameterMap().setParameters(statementScope, ps, parameters);
      ...
      ps.execute();
      rows = ps.getUpdateCount();
    } finally {
      closeStatement(statementScope.getSession(), ps);
    }

// SqlExecutor.java
private static PreparedStatement prepareStatement(SessionScope sessionScope, Connection conn, String sql) throws SQLException {
    ...
    if (sessionScope.hasPreparedStatementFor(sql)) {
      ...
    } else {
      PreparedStatement ps = conn.prepareStatement(sql);
      ...
      return ps;


// ParameterMap.java
public void setParameters(StatementScope statementScope, PreparedStatement ps, Object[] parameters) throws SQLException {
    ...
    if (parameterMappings != null) {
      for (int i = 0; i < parameterMappings.length; i++) {
        ParameterMapping mapping = parameterMappings[i];
        ...
        if (mapping.isInputAllowed()) {
          setParameter(ps, mapping, parameters, i);
        }
      }
    }



ref. 1 에 따르면, iBatis 는 autocommit 을 사용하지 않는다. 그리고 setCommitRequired() 은 AutoCommit 과는 관계없는 것이라고 한다. 자세한 내용은 ref.1 을 참고하자.


MyBatis 페이지에서 auto-commit 을 설정해서 session 을 여는 방법이 나온다. default 는 auto-commit 을 사용하지 않는 것이라고 한다.

  • MyBatis > SqlSessions > SqlSessionFactory > auto-commit



Method 이름

이상하게 method 하나를 만들었는데 auto-commit 이 되지 않았다. 이유는 method 이름에 있었다. AOP 의 설정이 아래와 같이 되어있어서 아래 조건에 맞지 않는 service 의 method 는 auto-commit 설정이 적용되지 않았던 것이었다.

aop 설정에 관해서는 나중에 알아보도록 하자.


//spring.xml

<!-- database -->

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
    <tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception"/>
    <tx:method name="edit*" propagation="REQUIRED" rollback-for="Exception"/>
    <tx:method name="add*" propagation="REQUIRED" rollback-for="Exception"/>
    <tx:method name="save*" propagation="REQUIRED" rollback-for="Exception"/>
    <tx:method name="init*" propagation="REQUIRED" rollback-for="Exception"/>
    <tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception"/>
    <tx:method name="udt*" propagation="REQUIRED" rollback-for="Exception"/>
    <tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/>
    <tx:method name="set*" propagation="REQUIRED" rollback-for="Exception"/>
    <tx:method name="change*" propagation="REQUIRED" rollback-for="Exception"/>
    </tx:attributes>
</tx:advice>

<aop:config>
    <aop:pointcut id="requiredTx"
        expression="execution(public * com.mine..service..*.*(..))" />
    <aop:advisor advice-ref="txAdvice"
        pointcut-ref="requiredTx" />

</aop:config>




Insert 후 Primary Key 를 받아오기


ref. 3, 4, 5 을 참고하자.

<insert id="insertVipData" parameterClass="VipInfo">

    INSERT INTO db1.test1 (user_id, c_id) VALUES (#USER_ID#, #C_ID#);

    <selectKey keyProperty="ID" resultClass="Integer">
      SELECT LAST_INSERT_ID()
    </selectKey>

</insert>




public class CdnStatVipInfo implements Serializable {
    
    ...
    private int ID; // ID
    public int getID() {
        return ID;
    }
    public void setID(int iD) {
        ID = iD;
    }


References

  1. Autocommit not properly handled in Ibatis, Jan 19, 2007
  2. 스프링 트래잭션 롤백이 되지 않을 때 확인 사항, 2013/03/05
  3.  [MySQL, iBATIS] LAST_INSERT_ID(), insert 후 PK 값 사용하기, 2010/01/25
  4. iBATIS - Create Operation
  5. iBatis에서 myBatis로 변경시 selectKey에 대한 변경사항, Posted 2013/05/04 12:08



댓글 없음:

댓글 쓰기