001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.jdbc.support; 018 019import javax.sql.DataSource; 020 021import org.apache.commons.logging.Log; 022import org.apache.commons.logging.LogFactory; 023 024import org.springframework.beans.factory.InitializingBean; 025 026/** 027 * Base class for {@link org.springframework.jdbc.core.JdbcTemplate} and 028 * other JDBC-accessing DAO helpers, defining common properties such as 029 * DataSource and exception translator. 030 * 031 * <p>Not intended to be used directly. 032 * See {@link org.springframework.jdbc.core.JdbcTemplate}. 033 * 034 * @author Juergen Hoeller 035 * @since 28.11.2003 036 * @see org.springframework.jdbc.core.JdbcTemplate 037 */ 038public abstract class JdbcAccessor implements InitializingBean { 039 040 /** Logger available to subclasses */ 041 protected final Log logger = LogFactory.getLog(getClass()); 042 043 private DataSource dataSource; 044 045 private volatile SQLExceptionTranslator exceptionTranslator; 046 047 private boolean lazyInit = true; 048 049 050 /** 051 * Set the JDBC DataSource to obtain connections from. 052 */ 053 public void setDataSource(DataSource dataSource) { 054 this.dataSource = dataSource; 055 } 056 057 /** 058 * Return the DataSource used by this template. 059 */ 060 public DataSource getDataSource() { 061 return this.dataSource; 062 } 063 064 /** 065 * Specify the database product name for the DataSource that this accessor uses. 066 * This allows to initialize a SQLErrorCodeSQLExceptionTranslator without 067 * obtaining a Connection from the DataSource to get the meta-data. 068 * @param dbName the database product name that identifies the error codes entry 069 * @see SQLErrorCodeSQLExceptionTranslator#setDatabaseProductName 070 * @see java.sql.DatabaseMetaData#getDatabaseProductName() 071 */ 072 public void setDatabaseProductName(String dbName) { 073 this.exceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(dbName); 074 } 075 076 /** 077 * Set the exception translator for this instance. 078 * <p>If no custom translator is provided, a default 079 * {@link SQLErrorCodeSQLExceptionTranslator} is used 080 * which examines the SQLException's vendor-specific error code. 081 * @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator 082 * @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator 083 */ 084 public void setExceptionTranslator(SQLExceptionTranslator exceptionTranslator) { 085 this.exceptionTranslator = exceptionTranslator; 086 } 087 088 /** 089 * Return the exception translator for this instance. 090 * <p>Creates a default {@link SQLErrorCodeSQLExceptionTranslator} 091 * for the specified DataSource if none set, or a 092 * {@link SQLStateSQLExceptionTranslator} in case of no DataSource. 093 * @see #getDataSource() 094 */ 095 public SQLExceptionTranslator getExceptionTranslator() { 096 SQLExceptionTranslator exceptionTranslator = this.exceptionTranslator; 097 if (exceptionTranslator != null) { 098 return exceptionTranslator; 099 } 100 synchronized (this) { 101 exceptionTranslator = this.exceptionTranslator; 102 if (exceptionTranslator == null) { 103 DataSource dataSource = getDataSource(); 104 if (dataSource != null) { 105 exceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(dataSource); 106 } 107 else { 108 exceptionTranslator = new SQLStateSQLExceptionTranslator(); 109 } 110 this.exceptionTranslator = exceptionTranslator; 111 } 112 return exceptionTranslator; 113 } 114 } 115 116 /** 117 * Set whether to lazily initialize the SQLExceptionTranslator for this accessor, 118 * on first encounter of a SQLException. Default is "true"; can be switched to 119 * "false" for initialization on startup. 120 * <p>Early initialization just applies if {@code afterPropertiesSet()} is called. 121 * @see #getExceptionTranslator() 122 * @see #afterPropertiesSet() 123 */ 124 public void setLazyInit(boolean lazyInit) { 125 this.lazyInit = lazyInit; 126 } 127 128 /** 129 * Return whether to lazily initialize the SQLExceptionTranslator for this accessor. 130 * @see #getExceptionTranslator() 131 */ 132 public boolean isLazyInit() { 133 return this.lazyInit; 134 } 135 136 /** 137 * Eagerly initialize the exception translator, if demanded, 138 * creating a default one for the specified DataSource if none set. 139 */ 140 @Override 141 public void afterPropertiesSet() { 142 if (getDataSource() == null) { 143 throw new IllegalArgumentException("Property 'dataSource' is required"); 144 } 145 if (!isLazyInit()) { 146 getExceptionTranslator(); 147 } 148 } 149 150}