SqlMapClient는 안전한 스레드입니다.
질문
private static SqlMapClient sqlMapper;
/**
* It's not a good idea to put code that can fail in a class initializer,
* but for sake of argument, here's how you configure an SQL Map.
*/
static {
try {
Reader reader = Resources.getResourceAsReader("com/mydomain/data/SqlMapConfig.xml");
sqlMapper = SqlMapClientBuilder.buildSqlMapClient(reader);
reader.close();
} catch (IOException e) {
// Fail fast.
throw new RuntimeException("Something bad happened while building the SqlMapClient instance." + e, e);
}
}
이것은 ibatis 단순 프로젝트의 코드입니다. 모두가 이것이 하나의 예라는 것을 알 수 있습니다. 단지 하나의 SqlMapClient 대상만 존재합니다. 다중 라인의 상황에서 SqlMapClient는 어떻게 사무 격리를 해결하고 자원을 공유하나요?
[newpage]
1. SqlMapClient가 어떻게 만들어졌는지
SqlMapClientBuilder를 열면buildsqlMapClien의 한마디 발견
public static SqlMapClient buildSqlMapClient(Reader reader) {
// return new XmlSqlMapClientBuilder().buildSqlMap(reader);
return new SqlMapConfigParser().parse(reader);
}
우리는 이 선을 따라 내려가 보았다
SqlMapConfigParser 클래스는 두 가지 일을 했다.reader를 NodeletParser에 넘겨서reader(즉 우리의 프로필)를 해석했다. 하나는 XmlParserState의 한 속성에 SqlMapClient 대상을 생성한다.
public class SqlMapConfigParser {
protected final NodeletParser parser = new NodeletParser();
private XmlParserState state = new XmlParserState();
public SqlMapClient parse(Reader reader) {
try {
usingStreams = false;
parser.parse(reader);
return state.getConfig().getClient();
} catch (Exception e) {
throw new RuntimeException("Error occurred. Cause: " + e, e);
}
}
NodeletParser의parse 방법을 열면 xml 프로필을 분석하는
public void parse(Reader reader) throws NodeletException {
try {
Document doc = createDocument(reader);
parse(doc.getLastChild());
} catch (Exception e) {
throw new NodeletException("Error parsing XML. Cause: " + e, e);
}
}
마지막으로 이 파일들은 XmlParserState의 속성에 분류되어 있습니다
private SqlMapConfiguration config = new SqlMapConfiguration();
private Properties globalProps = new Properties();
private Properties txProps = new Properties();
private Properties dsProps = new Properties();
private Properties cacheProps = new Properties();
private boolean useStatementNamespaces = false;
private Map sqlIncludes = new HashMap();
private ParameterMapConfig paramConfig;
private ResultMapConfig resultConfig;
private CacheModelConfig cacheConfig;
private String namespace;
private DataSource dataSource;
이제 우리는 고개를 돌려 Return state를 본다.getConfig().getClient();
이 말은 SqlMapClient 대상을 얻었다. 이 대상은 어떻게 만들었을까. SqlMapConfiguration의 구조 방법에서 이미 만들어졌다.
public SqlMapConfiguration() {
errorContext = new ErrorContext();
delegate = new SqlMapExecutorDelegate();
typeHandlerFactory = delegate.getTypeHandlerFactory();
client = new SqlMapClientImpl(delegate);
registerDefaultTypeAliases();
}
원래 우리가 도착한 것은 SqlMapClient(인터페이스가 실현될 수 없음) 대상이 아니라 그의 실현 SqlMapClientImpl이었다
2. SqlMapClientImpl 내부 깊이 들어가기
SqlMapClientImpl 클래스에는 세 개의 필드만 있습니다.
private static final Log log = LogFactory.getLog(SqlMapClientImpl.class);
public SqlMapExecutorDelegate delegate;
protected ThreadLocal localSqlMapSession = new ThreadLocal();
log는 로그 기록의 대상이므로 라인 안전과는 무관합니다
SqlMapExecutorDelegate라는 클래스에 뭐가 들어있을까요?
private static final Probe PROBE = ProbeFactory.getProbe();
private boolean lazyLoadingEnabled;
private boolean cacheModelsEnabled;
private boolean enhancementEnabled;
private boolean useColumnLabel = true;
private boolean forceMultipleResultSetSupport;
private TransactionManager txManager;
private HashMap mappedStatements;
private HashMap cacheModels;
private HashMap resultMaps;
private HashMap parameterMaps;
protected SqlExecutor sqlExecutor;
private TypeHandlerFactory typeHandlerFactory;
private DataExchangeFactory dataExchangeFactory;
private ResultObjectFactory resultObjectFactory;
private boolean statementCacheEnabled;
sqlMap , 。
localSqlMapSession , ,ThreadLocal , 。 Map localSqlMapSession,key id value localSqlMapSession 。
SqlMapClientImpl :
Java
public Object insert(String id, Object param) throws SQLException {
return getLocalSqlMapSession().insert(id, param);
}
public Object insert(String id) throws SQLException {
return getLocalSqlMapSession().insert(id);
}
public int update(String id, Object param) throws SQLException {
return getLocalSqlMapSession().update(id, param);
}
public int update(String id) throws SQLException {
return getLocalSqlMapSession().update(id);
}
public int delete(String id, Object param) throws SQLException {
return getLocalSqlMapSession().delete(id, param);
}
public int delete(String id) throws SQLException {
return getLocalSqlMapSession().delete(id);
}
public Object queryForObject(String id, Object paramObject) throws SQLException {
return getLocalSqlMapSession().queryForObject(id, paramObject);
}
얼마나 익숙한 방법인가, 이것이 바로 우리가 자주 사용하는curd의 방법이다.코드에서 우리의 추측을 증명하였는데, 스레드 안전은localSqlMapSession과 관련이 있다
관련 속성을 찾았지만 그들은 어떻게 이뤘을까.
3. 라인의 안전한 실현.
dao 부분의 라인 안전에 있어 하나는 주로 업무의 완성성이다.만약 사무가 완전성을 보장할 수 있다면, 라인이 안전하다고 말할 수 있다.
localSqlMapSession에 저장된 것은 무엇입니까? 코드를 열어 봅시다.
protected SqlMapSessionImpl getLocalSqlMapSession() {
SqlMapSessionImpl sqlMapSession = (SqlMapSessionImpl) localSqlMapSession.get();
if (sqlMapSession == null || sqlMapSession.isClosed()) {
sqlMapSession = new SqlMapSessionImpl(this);
localSqlMapSession.set(sqlMapSession);
}
return sqlMapSession;
}
SqlMapSessionImpl을 다시 한 번 연구해 보자. 이 종류는 세 개의 필드만 있다.
protected SqlMapExecutorDelegate delegate;
protected SessionScope sessionScope;
protected boolean closed;
분명히 SessionScope. 저희가 찾는 물건이에요.
private static long nextId;
private long id;
// Used by Any
private SqlMapClient sqlMapClient;
private SqlMapExecutor sqlMapExecutor;
private SqlMapTransactionManager sqlMapTxMgr;
private int requestStackDepth;
// Used by TransactionManager
private Transaction transaction;
private TransactionState transactionState;
// Used by SqlMapExecutorDelegate.setUserProvidedTransaction()
private TransactionState savedTransactionState;
// Used by StandardSqlMapClient and GeneralStatement
private boolean inBatch;
// Used by SqlExecutor
private Object batch;
private boolean commitRequired;
private Map preparedStatements
; 우리의 분석 업무의 완전성은dao층의 라인 안전을 충분히 보장할 수 있다.Transaction은ThreadLocal에 저장되어 SqlMapClient가 라인이 안전하다는 것을 증명했다. 우리는 전체 프로젝트에서 SqlMapClient 대상만 있으면 충분하다.
SessionScope 클래스의 필드를 살펴보겠습니다.
private SqlMapClient sqlMapClient; SqlMapClient
private SqlMapExecutor sqlMapExecutor; sql
private SqlMapTransactionManager sqlMapTxMgr;
private int requestStackDepth;
// Used by TransactionManager
private Transaction transaction;
private TransactionState transactionState;
// Used by SqlMapExecutorDelegate.setUserProvidedTransaction()
private TransactionState savedTransactionState;
// Used by StandardSqlMapClient and GeneralStatement
private boolean inBatch;
// Used by SqlExecutor
private Object batch;
private boolean commitRequired;
private Map preparedStatements; PreparedStatement
우리는 연결류 연결이 없다는 것을 갑자기 발견했다. 만약 jdbc를 사용한다면 연결이 얼마나 중요한 대상인지, 여기에 연결이 저장되어 있지 않은지.JdbcTransaction 열기(하나의 Transaction 실행)
private static final Log connectionLog = LogFactory.getLog(Connection.class);
private DataSource dataSource;
private Connection connection;
private IsolationLevel isolationLevel = new IsolationLevel();
public JdbcTransaction(DataSource ds, int isolationLevel) throws TransactionException {
// Check Parameters
dataSource = ds;
if (dataSource == null) {
throw new TransactionException("JdbcTransaction initialization failed. DataSource was null.");
}
this.isolationLevel.setIsolationLevel(isolationLevel);
}
private void init() throws SQLException, TransactionException {
// Open JDBC Transaction
connection = dataSource.getConnection();
if (connection == null) {
throw new TransactionException("JdbcTransaction could not start transaction. Cause: The DataSource returned a null connection.");
}
// Isolation Level
isolationLevel.applyIsolationLevel(connection);
// AutoCommit
if (connection.getAutoCommit()) {
connection.setAutoCommit(false);
}
// Debug
if (connectionLog.isDebugEnabled()) {
connection = ConnectionLogProxy.newInstance(connection);
}
}
public void commit() throws SQLException, TransactionException {
if (connection != null) {
connection.commit();
}
}
public void rollback() throws SQLException, TransactionException {
if (connection != null) {
connection.rollback();
}
}
public void close() throws SQLException, TransactionException {
if (connection != null) {
try {
isolationLevel.restoreIsolationLevel(connection);
} finally {
connection.close();
connection = null;
}
}
}
public Connection getConnection() throws SQLException, TransactionException {
if (connection == null) {
init();
}
return connection;
}
원래 Connection이 여기에 저장되어 있었군요. 업무의 제출, 스크롤도 이곳에서 이루어졌습니다.
여기서 대체적으로 알 수 있듯이ibatis는 모든 SqlMapClient를 조작하는 라인에SessionScope 대상을 만들고 이 안에는Transaction,Connection,실행할 PreparedStatement가 저장되어 있다.
SqlMapClient 대상에는 전역 관련 캐시 정책,ParameterMap,ResultMap,jdbc에서 자바 대상으로의 유형 변환, 별명 등 정보가 저장되어 있습니다.
실행되는 Statement마다 StatementScope가 하나 더 있습니다. 여기에 저장된 것은 모든 실행 문장의 상태입니다.여기는 안 볼게요.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Spring에서 DAO가 순환 호출될 때 데이터가 실시간으로 업데이트되지 않는 해결 방법문제를 설명하기 전에 몇 가지 전제 사항을 설명하십시오. Spring의 구성 파일에서 다음과 같은 방식으로 데이터베이스 트랜잭션을 구성했다고 가정하십시오. 현재 UserDao 및 Security Service가 있습...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.