public Builder( Configuration configuration, String id, SqlSource sqlSource, SqlCommandType sqlCommandType) { mappedStatement.configuration = configuration; mappedStatement.id = id; mappedStatement.sqlSource = sqlSource; mappedStatement.statementType = StatementType.PREPARED; mappedStatement.parameterMap = new ParameterMap.Builder( configuration, "defaultParameterMap", null, new ArrayList<ParameterMapping>()) .build(); mappedStatement.resultMaps = new ArrayList<ResultMap>(); mappedStatement.timeout = configuration.getDefaultStatementTimeout(); mappedStatement.sqlCommandType = sqlCommandType; mappedStatement.keyGenerator = configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType) ? new Jdbc3KeyGenerator() : new NoKeyGenerator(); String logId = id; if (configuration.getLogPrefix() != null) logId = configuration.getLogPrefix() + id; mappedStatement.statementLog = LogFactory.getLog(logId); mappedStatement.lang = configuration.getDefaultScriptingLanuageInstance(); }
@Override public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { if (!isStart) { /** 导入操作记录数据 */ // fileContentParser.initOperate(); isStart = true; org.apache.ibatis.logging.LogFactory.useSlf4jLogging(); } }
/** * @author LeeWonHee * @since 2015.09.22 */ public class MemberDAOImpl implements MemberDAO { protected Log log = LogFactory.getLog(this.getClass()); private SqlSessionTemplate sqlMap; public MemberDAOImpl(SqlSessionTemplate sqlMap) { super(); this.sqlMap = sqlMap; } protected void printQueryId(String queryId) { if (log.isDebugEnabled()) { log.debug("\t QueryId \t : " + queryId); } } @Override public int join(String queryId, MemberDTO dto) throws DataAccessException { printQueryId(queryId); return sqlMap.insert("insertMember", dto); } @Override public MemberDTO getMemberInfo(String queryId, String id) throws DataAccessException { printQueryId(queryId); return sqlMap.selectOne("selectMember", id); } @Override public int updateMemberInfo(String queryId, String id) throws DataAccessException { printQueryId(queryId); return sqlMap.update("updateMember", id); } @Override public int deleteMember(String queryId, String id) throws DataAccessException { printQueryId(queryId); return sqlMap.update("deleteMember", id); } }
/** * created by tom on 15/10/08 通过拦截<code>StatementHandler</code>的 <code>prepare</code> * 方法,重写sql语句实现物理分页。 老规矩,签名里要拦截的类型只能是接口。 专门为bootstrap设计 mybatis 分页拦截器 */ @Intercepts({ @Signature( type = StatementHandler.class, method = "prepare", args = {Connection.class}) }) public class PaginationInterceptor implements Interceptor { private static final Log logger = LogFactory.getLog(PaginationInterceptor.class); private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory(); private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory(); private static final ReflectorFactory DEFAULT_REFLECTOR_FACTORY = new DefaultReflectorFactory(); private static final String defaultDialect = "mysql"; private static final String defaultPageSqlId = ".*Page$"; private String dialect; private String pageSqlId; @Override public Object intercept(Invocation invocation) throws Throwable { StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); MetaObject metaStatementHandler = MetaObject.forObject( statementHandler, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY); // 分离代理对象链(由于目标类可能被多个拦截器拦截,从而形成多次代理,通过下面的两次循环 // 可以分离出最原始的的目标类) while (metaStatementHandler.hasGetter("h")) { Object object = metaStatementHandler.getValue("h"); metaStatementHandler = MetaObject.forObject( object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY); } // 分离最后一个代理对象的目标类 while (metaStatementHandler.hasGetter("target")) { Object object = metaStatementHandler.getValue("target"); metaStatementHandler = MetaObject.forObject( object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY); } if (null == dialect || "".equals(dialect)) { logger.warn("Property dialect is not setted,use default 'mysql' "); dialect = defaultDialect; } if (null == pageSqlId || "".equals(pageSqlId)) { logger.warn("Property pageSqlId is not setted,use default '.*Page$' "); pageSqlId = defaultPageSqlId; } MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement"); PageParameter page = null; Object type = metaStatementHandler.getValue("delegate.boundSql.parameterObject"); if (PageParameter.class.isInstance(type)) { page = (PageParameter) type; } // 只重写需要分页的sql语句。通过MappedStatement的ID匹配,默认重写以Page结尾的 // MappedStatement的sql if (mappedStatement.getId().matches(pageSqlId) && page != null && page.getLimit() > 0) { BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql"); Object parameterObject = boundSql.getParameterObject(); if (parameterObject == null) { throw new NullPointerException("parameterObject is null!"); } else { // 分页参数作为参数对象parameterObject的一个属性 String sql = boundSql.getSql(); // 重写sql String pageSql = buildPageSql(sql, page, dialect); metaStatementHandler.setValue("delegate.boundSql.sql", pageSql); // 采用物理分页后,就不需要mybatis的内存分页了,所以重置下面的两个参数 metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET); metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT); Connection connection = (Connection) invocation.getArgs()[0]; // 重设分页参数里的总页数等 setPageParameter(sql, connection, mappedStatement, boundSql, page); } } // 将执行权交给下一个拦截器 return invocation.proceed(); } private String buildPageSql(String sql, PageParameter page, String dialect) { if (page != null) { StringBuilder pageSql = new StringBuilder(); if ("mysql".equals(dialect)) { pageSql = buildPageSqlForMysql(sql, page); } else if ("oracle".equals(dialect)) { pageSql = buildPageSqlForOracle(sql, page); } else { return sql; } return pageSql.toString(); } else { return sql; } } @Override public Object plugin(Object target) { // 当目标类是StatementHandler类型时,才包装目标类,否者直接返回目标本身,减少目标被代理的次数 if (target instanceof StatementHandler) { return Plugin.wrap(target, this); } else { return target; } } @Override public void setProperties(Properties properties) { // To change body of implemented methods use File | Settings | File // Templates. } public StringBuilder buildPageSqlForMysql(String sql, PageParameter page) { StringBuilder pageSql = new StringBuilder(100); pageSql.append(sql); pageSql.append(" limit " + page.getOffset() + "," + page.getLimit()); return pageSql; } public StringBuilder buildPageSqlForOracle(String sql, PageParameter page) { StringBuilder pageSql = new StringBuilder(100); String beginrow = String.valueOf((page.getCurrentPage() - 1) * page.getPageSize()); String endrow = String.valueOf(page.getCurrentPage() * page.getPageSize()); pageSql.append("select * from ( select temp.*, rownum row_id from ( "); pageSql.append(sql); pageSql.append(" ) temp where rownum <= ").append(endrow); pageSql.append(") where row_id > ").append(beginrow); return pageSql; } /** * 从数据库里查询总的记录数并计算总页数,回写进分页参数<code>PageParameter</code>,这样调用 者就可用通过 分页参数 <code>PageParameter * </code>获得相关信息。 * * @param sql * @param connection * @param mappedStatement * @param boundSql * @param page */ private void setPageParameter( String sql, Connection connection, MappedStatement mappedStatement, BoundSql boundSql, PageParameter page) { // 记录总记录数 String countSql = "select count(0) as total from (" + sql + ") tt"; PreparedStatement countStmt = null; ResultSet rs = null; try { countStmt = connection.prepareStatement(countSql); setParameters(countStmt, mappedStatement, boundSql); rs = countStmt.executeQuery(); int totalCount = 0; if (rs.next()) { totalCount = rs.getInt(1); } page.setTotalElements(totalCount); // int totalPage = totalCount / page.getPageSize() + ((totalCount % page.getPageSize() == 0) // ? 0 : 1); // page.setTotalPage(totalPage); } catch (SQLException e) { logger.error("Ignore this exception", e); } finally { try { rs.close(); } catch (SQLException e) { logger.error("Ignore this exception", e); } try { countStmt.close(); } catch (SQLException e) { logger.error("Ignore this exception", e); } } } /** * 对SQL参数(?)设值 * * @param ps * @param mappedStatement * @param boundSql * @param parameterObject * @throws SQLException */ private void setParameters( PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql) throws SQLException { ParameterHandler parameterHandler = mappedStatement .getConfiguration() .newParameterHandler(mappedStatement, boundSql.getParameterObject(), boundSql); parameterHandler.setParameters(ps); } public void setDialect(String dialect) { this.dialect = dialect; } public void setPageSqlId(String pageSqlId) { this.pageSqlId = pageSqlId; } }
public MyBatis start() { LogFactory.useSlf4jLogging(); MyBatisConfBuilder confBuilder = new MyBatisConfBuilder(database); // DTO aliases, keep them sorted alphabetically confBuilder.loadAlias("ActiveDashboard", ActiveDashboardDto.class); confBuilder.loadAlias("ActiveRule", ActiveRuleDto.class); confBuilder.loadAlias("ActiveRuleParam", ActiveRuleParamDto.class); confBuilder.loadAlias("Author", AuthorDto.class); confBuilder.loadAlias("Component", ComponentDto.class); confBuilder.loadAlias("ComponentLink", ComponentLinkDto.class); confBuilder.loadAlias("ComponentWithSnapshot", ComponentDtoWithSnapshotId.class); confBuilder.loadAlias("CustomMeasure", CustomMeasureDto.class); confBuilder.loadAlias("Dashboard", DashboardDto.class); confBuilder.loadAlias("DuplicationUnit", DuplicationUnitDto.class); confBuilder.loadAlias("Event", EventDto.class); confBuilder.loadAlias("FilePathWithHash", FilePathWithHashDto.class); confBuilder.loadAlias("Group", GroupDto.class); confBuilder.loadAlias("GroupMembership", GroupMembershipDto.class); confBuilder.loadAlias("GroupPermission", GroupPermissionDto.class); confBuilder.loadAlias("IdUuidPair", IdUuidPair.class); confBuilder.loadAlias("InternalProperty", InternalPropertyDto.class); confBuilder.loadAlias("IssueChange", IssueChangeDto.class); confBuilder.loadAlias("IssueFilterFavourite", IssueFilterFavouriteDto.class); confBuilder.loadAlias("IssueFilter", IssueFilterDto.class); confBuilder.loadAlias("Issue", IssueDto.class); confBuilder.loadAlias("LoadedTemplate", LoadedTemplateDto.class); confBuilder.loadAlias("MeasureFilterFavourite", MeasureFilterFavouriteDto.class); confBuilder.loadAlias("MeasureFilter", MeasureFilterDto.class); confBuilder.loadAlias("Measure", MeasureDto.class); confBuilder.loadAlias("NotificationQueue", NotificationQueueDto.class); confBuilder.loadAlias("Organization", OrganizationDto.class); confBuilder.loadAlias( "PermissionTemplateCharacteristic", PermissionTemplateCharacteristicDto.class); confBuilder.loadAlias("PermissionTemplateGroup", PermissionTemplateGroupDto.class); confBuilder.loadAlias("PermissionTemplate", PermissionTemplateDto.class); confBuilder.loadAlias("PermissionTemplateUser", PermissionTemplateUserDto.class); confBuilder.loadAlias("ProjectQgateAssociation", ProjectQgateAssociationDto.class); confBuilder.loadAlias("PurgeableAnalysis", PurgeableAnalysisDto.class); confBuilder.loadAlias("QualityGateCondition", QualityGateConditionDto.class); confBuilder.loadAlias("QualityGate", QualityGateDto.class); confBuilder.loadAlias("QualityProfile", QualityProfileDto.class); confBuilder.loadAlias("RequirementMigration", RequirementMigrationDto.class); confBuilder.loadAlias("ResourceIndex", ResourceIndexDto.class); confBuilder.loadAlias("Resource", ResourceDto.class); confBuilder.loadAlias("RuleParam", RuleParamDto.class); confBuilder.loadAlias("Rule", RuleDto.class); confBuilder.loadAlias("SchemaMigration", SchemaMigrationDto.class); confBuilder.loadAlias("ScrapProperty", ScrapPropertyDto.class); confBuilder.loadAlias("Snapshot", SnapshotDto.class); confBuilder.loadAlias("UserGroup", UserGroupDto.class); confBuilder.loadAlias("UserPermission", UserPermissionDto.class); confBuilder.loadAlias("UserTokenCount", UserTokenCount.class); confBuilder.loadAlias("UserToken", UserTokenDto.class); confBuilder.loadAlias("User", UserDto.class); confBuilder.loadAlias("UuidWithProjectUuid", UuidWithProjectUuidDto.class); confBuilder.loadAlias("ViewsSnapshot", ViewsSnapshotDto.class); confBuilder.loadAlias("WidgetProperty", WidgetPropertyDto.class); confBuilder.loadAlias("Widget", WidgetDto.class); // ResourceMapper has to be loaded before IssueMapper because this last one used it confBuilder.loadMapper(ResourceMapper.class); // keep them sorted alphabetically Class<?>[] mappers = { ActiveDashboardMapper.class, ActiveRuleMapper.class, AuthorMapper.class, CeActivityMapper.class, CeQueueMapper.class, CeScannerContextMapper.class, CeTaskInputMapper.class, ComponentKeyUpdaterMapper.class, ComponentLinkMapper.class, ComponentMapper.class, CustomMeasureMapper.class, DashboardMapper.class, DuplicationMapper.class, EventMapper.class, FileSourceMapper.class, GroupMapper.class, GroupMembershipMapper.class, GroupPermissionMapper.class, InternalPropertiesMapper.class, IsAliveMapper.class, IssueChangeMapper.class, IssueFilterFavouriteMapper.class, IssueFilterMapper.class, IssueMapper.class, LoadedTemplateMapper.class, MeasureFilterFavouriteMapper.class, MeasureFilterMapper.class, MeasureMapper.class, MetricMapper.class, Migration45Mapper.class, Migration50Mapper.class, Migration53Mapper.class, NotificationQueueMapper.class, OrganizationMapper.class, PermissionMapper.class, PermissionTemplateCharacteristicMapper.class, PermissionTemplateMapper.class, ProjectQgateAssociationMapper.class, PropertiesMapper.class, PurgeMapper.class, QProfileChangeMapper.class, QualityGateConditionMapper.class, QualityGateMapper.class, QualityProfileMapper.class, ResourceIndexMapper.class, RoleMapper.class, RuleMapper.class, RuleRepositoryMapper.class, SchemaMigrationMapper.class, SnapshotMapper.class, UserGroupMapper.class, UserMapper.class, UserPermissionMapper.class, UserTokenMapper.class, WidgetMapper.class, WidgetPropertyMapper.class }; confBuilder.loadMappers(mappers); sessionFactory = new SqlSessionFactoryBuilder().build(confBuilder.build()); return this; }
/** * {@code FactoryBean} that creates an MyBatis {@code SqlSessionFactory}. This is the usual way to * set up a shared MyBatis {@code SqlSessionFactory} in a Spring application context; the * SqlSessionFactory can then be passed to MyBatis-based DAOs via dependency injection. * * <p>Either {@code DataSourceTransactionManager} or {@code JtaTransactionManager} can be used for * transaction demarcation in combination with a {@code SqlSessionFactory}. JTA should be used for * transactions which span multiple databases or when container managed transactions (CMT) are being * used. * * @see #setConfigLocation * @see #setDataSource * @version $Id$ */ public class SqlSessionFactoryBeanMultiple implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> { // private static Logger log = Logger.getLogger(SqlSessionFactoryBeanMultiple.class); private final Log logger = LogFactory.getLog(getClass()); private Resource configLocation; private Resource[] mapperLocations; private Resource[] mapperLocations1; private Resource[] mapperLocations2; private Resource[] mapperLocations3; private Resource[] mapperLocations4; private DataSource dataSource; private TransactionFactory transactionFactory; private Properties configurationProperties; private SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); private SqlSessionFactory sqlSessionFactory; private String environment = SqlSessionFactoryBeanMultiple.class.getSimpleName(); // EnvironmentAware requires spring 3.1 private boolean failFast; private Interceptor[] plugins; private TypeHandler<?>[] typeHandlers; private String typeHandlersPackage; private Class<?>[] typeAliases; private String typeAliasesPackage; private Class<?> typeAliasesSuperType; private DatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider(); private ObjectFactory objectFactory; private ObjectWrapperFactory objectWrapperFactory; /** * Sets the ObjectFactory. * * @since 1.1.2 * @param objectFactory */ public void setObjectFactory(ObjectFactory objectFactory) { this.objectFactory = objectFactory; } /** * Sets the ObjectWrapperFactory. * * @since 1.1.2 * @param objectWrapperFactory */ public void setObjectWrapperFactory(ObjectWrapperFactory objectWrapperFactory) { this.objectWrapperFactory = objectWrapperFactory; } /** * Sets the DatabaseIdProvider. * * @since 1.1.0 * @return */ public DatabaseIdProvider getDatabaseIdProvider() { return databaseIdProvider; } /** * Gets the DatabaseIdProvider * * @since 1.1.0 * @param databaseIdProvider */ public void setDatabaseIdProvider(DatabaseIdProvider databaseIdProvider) { this.databaseIdProvider = databaseIdProvider; } /** * Mybatis plugin list. * * @since 1.0.1 * @param plugins list of plugins */ public void setPlugins(Interceptor[] plugins) { this.plugins = plugins; } /** * Packages to search for type aliases. * * @since 1.0.1 * @param typeAliasesPackage package to scan for domain objects */ public void setTypeAliasesPackage(String typeAliasesPackage) { this.typeAliasesPackage = typeAliasesPackage; } /** * Super class which domain objects have to extend to have a type alias created. No effect if * there is no package to scan configured. * * @since 1.1.2 * @param typeAliasesSuperType super class for domain objects */ public void setTypeAliasesSuperType(Class<?> typeAliasesSuperType) { this.typeAliasesSuperType = typeAliasesSuperType; } /** * Packages to search for type handlers. * * @since 1.0.1 * @param typeHandlersPackage package to scan for type handlers */ public void setTypeHandlersPackage(String typeHandlersPackage) { this.typeHandlersPackage = typeHandlersPackage; } /** * Set type handlers. They must be annotated with {@code MappedTypes} and optionally with {@code * MappedJdbcTypes} * * @since 1.0.1 * @param typeHandlers Type handler list */ public void setTypeHandlers(TypeHandler<?>[] typeHandlers) { this.typeHandlers = typeHandlers; } /** * List of type aliases to register. They can be annotated with {@code Alias} * * @since 1.0.1 * @param typeAliases Type aliases list */ public void setTypeAliases(Class<?>[] typeAliases) { this.typeAliases = typeAliases; } /** * If true, a final check is done on Configuration to assure that all mapped statements are fully * loaded and there is no one still pending to resolve includes. Defaults to false. * * @since 1.0.1 * @param failFast enable failFast */ public void setFailFast(boolean failFast) { this.failFast = failFast; } /** * Set the location of the MyBatis {@code SqlSessionFactory} config file. A typical value is * "WEB-INF/mybatis-configuration.xml". */ public void setConfigLocation(Resource configLocation) { this.configLocation = configLocation; } /** * Set locations of MyBatis mapper files that are going to be merged into the {@code * SqlSessionFactory} configuration at runtime. * * <p>This is an alternative to specifying "<sqlmapper>" entries in an MyBatis config file. * This property being based on Spring's resource abstraction also allows for specifying resource * patterns here: e.g. "classpath*:sqlmap/*-mapper.xml". */ public void setMapperLocations1(Resource[] mapperLocations) { this.mapperLocations1 = mapperLocations; } /** * Set locations of MyBatis mapper files that are going to be merged into the {@code * SqlSessionFactory} configuration at runtime. * * <p>This is an alternative to specifying "<sqlmapper>" entries in an MyBatis config file. * This property being based on Spring's resource abstraction also allows for specifying resource * patterns here: e.g. "classpath*:sqlmap/*-mapper.xml". */ public void setMapperLocations2(Resource[] mapperLocations) { this.mapperLocations2 = mapperLocations; } /** * Set locations of MyBatis mapper files that are going to be merged into the {@code * SqlSessionFactory} configuration at runtime. * * <p>This is an alternative to specifying "<sqlmapper>" entries in an MyBatis config file. * This property being based on Spring's resource abstraction also allows for specifying resource * patterns here: e.g. "classpath*:sqlmap/*-mapper.xml". */ public void setMapperLocations3(Resource[] mapperLocations) { this.mapperLocations3 = mapperLocations; } public void setMapperLocations4(Resource[] mapperLocations) { this.mapperLocations4 = mapperLocations; } /** * Set optional properties to be passed into the SqlSession configuration, as alternative to a * {@code <properties>} tag in the configuration xml file. This will be used to resolve * placeholders in the config file. */ public void setConfigurationProperties(Properties sqlSessionFactoryProperties) { this.configurationProperties = sqlSessionFactoryProperties; } /** * Set the JDBC {@code DataSource} that this instance should manage transactions for. The {@code * DataSource} should match the one used by the {@code SqlSessionFactory}: for example, you could * specify the same JNDI DataSource for both. * * <p>A transactional JDBC {@code Connection} for this {@code DataSource} will be provided to * application code accessing this {@code DataSource} directly via {@code DataSourceUtils} or * {@code DataSourceTransactionManager}. * * <p>The {@code DataSource} specified here should be the target {@code DataSource} to manage * transactions for, not a {@code TransactionAwareDataSourceProxy}. Only data access code may work * with {@code TransactionAwareDataSourceProxy}, while the transaction manager needs to work on * the underlying target {@code DataSource}. If there's nevertheless a {@code * TransactionAwareDataSourceProxy} passed in, it will be unwrapped to extract its target {@code * DataSource}. */ public void setDataSource(DataSource dataSource) { if (dataSource instanceof TransactionAwareDataSourceProxy) { // If we got a TransactionAwareDataSourceProxy, we need to perform // transactions for its underlying target DataSource, else data // access code won't see properly exposed transactions (i.e. // transactions for the target DataSource). this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource(); } else { this.dataSource = dataSource; } } /** * Sets the {@code SqlSessionFactoryBuilder} to use when creating the {@code SqlSessionFactory}. * * <p>This is mainly meant for testing so that mock SqlSessionFactory classes can be injected. By * default, {@code SqlSessionFactoryBuilder} creates {@code DefaultSqlSessionFactory} instances. */ public void setSqlSessionFactoryBuilder(SqlSessionFactoryBuilder sqlSessionFactoryBuilder) { this.sqlSessionFactoryBuilder = sqlSessionFactoryBuilder; } /** * Set the MyBatis TransactionFactory to use. Default is {@code SpringManagedTransactionFactory} * * <p>The default {@code SpringManagedTransactionFactory} should be appropriate for all cases: be * it Spring transaction management, EJB CMT or plain JTA. If there is no active transaction, * SqlSession operations will execute SQL statements non-transactionally. * * <p><b>It is strongly recommended to use the default {@code TransactionFactory}.</b> If not * used, any attempt at getting an SqlSession through Spring's MyBatis framework will throw an * exception if a transaction is active. * * @see SpringManagedTransactionFactory * @param transactionFactory the MyBatis TransactionFactory */ public void setTransactionFactory(TransactionFactory transactionFactory) { this.transactionFactory = transactionFactory; } /** * <b>NOTE:</b> This class <em>overrides</em> any {@code Environment} you have set in the MyBatis * config file. This is used only as a placeholder name. The default value is {@code * SqlSessionFactoryBean.class.getSimpleName()}. * * @param environment the environment name */ public void setEnvironment(String environment) { this.environment = environment; } /** {@inheritDoc} */ public void afterPropertiesSet() throws Exception { notNull(dataSource, "Property 'dataSource' is required"); notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required"); this.sqlSessionFactory = buildSqlSessionFactory(); } /** * Build a {@code SqlSessionFactory} instance. * * <p>The default implementation uses the standard MyBatis {@code XMLConfigBuilder} API to build a * {@code SqlSessionFactory} instance based on an Reader. * * @return SqlSessionFactory * @throws IOException if loading the config file failed */ protected SqlSessionFactory buildSqlSessionFactory() throws IOException { Configuration configuration; XMLConfigBuilder xmlConfigBuilder = null; if (this.configLocation != null) { xmlConfigBuilder = new XMLConfigBuilder( this.configLocation.getInputStream(), null, this.configurationProperties); configuration = xmlConfigBuilder.getConfiguration(); } else { if (this.logger.isDebugEnabled()) { this.logger.debug( "Property 'configLocation' not specified, using default MyBatis Configuration"); } configuration = new Configuration(); configuration.setVariables(this.configurationProperties); } if (this.objectFactory != null) { configuration.setObjectFactory(this.objectFactory); } if (this.objectWrapperFactory != null) { configuration.setObjectWrapperFactory(this.objectWrapperFactory); } if (hasLength(this.typeAliasesPackage)) { String[] typeAliasPackageArray = tokenizeToStringArray( this.typeAliasesPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); for (String packageToScan : typeAliasPackageArray) { configuration .getTypeAliasRegistry() .registerAliases( packageToScan, typeAliasesSuperType == null ? Object.class : typeAliasesSuperType); if (this.logger.isDebugEnabled()) { this.logger.debug("Scanned package: '" + packageToScan + "' for aliases"); } } } if (!isEmpty(this.typeAliases)) { for (Class<?> typeAlias : this.typeAliases) { configuration.getTypeAliasRegistry().registerAlias(typeAlias); if (this.logger.isDebugEnabled()) { this.logger.debug("Registered type alias: '" + typeAlias + "'"); } } } if (!isEmpty(this.plugins)) { for (Interceptor plugin : this.plugins) { configuration.addInterceptor(plugin); if (this.logger.isDebugEnabled()) { this.logger.debug("Registered plugin: '" + plugin + "'"); } } } if (hasLength(this.typeHandlersPackage)) { String[] typeHandlersPackageArray = tokenizeToStringArray( this.typeHandlersPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); for (String packageToScan : typeHandlersPackageArray) { configuration.getTypeHandlerRegistry().register(packageToScan); if (this.logger.isDebugEnabled()) { this.logger.debug("Scanned package: '" + packageToScan + "' for type handlers"); } } } if (!isEmpty(this.typeHandlers)) { for (TypeHandler<?> typeHandler : this.typeHandlers) { configuration.getTypeHandlerRegistry().register(typeHandler); if (this.logger.isDebugEnabled()) { this.logger.debug("Registered type handler: '" + typeHandler + "'"); } } } if (xmlConfigBuilder != null) { try { xmlConfigBuilder.parse(); if (this.logger.isDebugEnabled()) { this.logger.debug("Parsed configuration file: '" + this.configLocation + "'"); } } catch (Exception ex) { throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex); } finally { ErrorContext.instance().reset(); } } if (this.transactionFactory == null) { this.transactionFactory = new SpringManagedTransactionFactory(); } Environment environment = new Environment(this.environment, this.transactionFactory, this.dataSource); configuration.setEnvironment(environment); if (this.databaseIdProvider != null) { try { configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource)); } catch (SQLException e) { throw new NestedIOException("Failed getting a databaseId", e); } } ArrayList<Resource> listado_resources = new ArrayList<Resource>(); if (!isEmpty(this.mapperLocations1)) { for (Resource resource : this.mapperLocations1) { listado_resources.add(resource); } } if (!isEmpty(this.mapperLocations2)) { for (Resource resource : this.mapperLocations2) { listado_resources.add(resource); } } if (!isEmpty(this.mapperLocations3)) { for (Resource resource : this.mapperLocations3) { listado_resources.add(resource); } } if (!isEmpty(this.mapperLocations4)) { for (Resource resource : this.mapperLocations4) { listado_resources.add(resource); } } this.mapperLocations = new Resource[listado_resources.size()]; int index = 0; for (Resource resource : listado_resources) { this.mapperLocations[index] = resource; index++; } if (!isEmpty(this.mapperLocations)) { for (Resource mapperLocation : this.mapperLocations) { if (mapperLocation == null) { continue; } // //log.info("Mapa cargado: " + mapperLocation); try { XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder( mapperLocation.getInputStream(), configuration, mapperLocation.toString(), configuration.getSqlFragments()); xmlMapperBuilder.parse(); } catch (Exception e) { throw new NestedIOException( "Failed to parse mapping resource: '" + mapperLocation + "'", e); } finally { ErrorContext.instance().reset(); } if (this.logger.isDebugEnabled()) { this.logger.debug("Parsed mapper file: '" + mapperLocation + "'"); } } } else { if (this.logger.isDebugEnabled()) { this.logger.debug( "Property 'mapperLocations' was not specified or no matching resources found"); } } return this.sqlSessionFactoryBuilder.build(configuration); } /** {@inheritDoc} */ public SqlSessionFactory getObject() throws Exception { if (this.sqlSessionFactory == null) { afterPropertiesSet(); } return this.sqlSessionFactory; } /** {@inheritDoc} */ public Class<? extends SqlSessionFactory> getObjectType() { return this.sqlSessionFactory == null ? SqlSessionFactory.class : this.sqlSessionFactory.getClass(); } /** {@inheritDoc} */ public boolean isSingleton() { return true; } /** {@inheritDoc} */ public void onApplicationEvent(ApplicationEvent event) { if (failFast && event instanceof ContextRefreshedEvent) { // fail-fast -> check all statements are completed this.sqlSessionFactory.getConfiguration().getMappedStatementNames(); } } }
/** * Mybatis分页拦截器基类 * * @author poplar.yfyang / ssmas * @version 2013-8-28 */ public abstract class BaseInterceptor implements Interceptor, Serializable { private static final long serialVersionUID = 1L; protected static final String PAGE = "page"; protected static final String DELEGATE = "delegate"; protected static final String MAPPED_STATEMENT = "mappedStatement"; protected Log log = LogFactory.getLog(this.getClass()); protected Dialect DIALECT; // /** // * 拦截的ID,在mapper中的id,可以匹配正则 // */ // protected String _SQL_PATTERN = ""; /** * 对参数进行转换和检查 * * @param parameterObject 参数对象 * @param page 分页对象 * @return 分页对象 * @throws NoSuchFieldException 无法找到参数 */ @SuppressWarnings("unchecked") protected static Page<Object> convertParameter(Object parameterObject, Page<Object> page) { try { if (parameterObject instanceof Page) { return (Page<Object>) parameterObject; } else { return (Page<Object>) Reflections.getFieldValue(parameterObject, PAGE); } } catch (Exception e) { return null; } } /** * 设置属性,支持自定义方言类和制定数据库的方式 <code>dialectClass</code>,自定义方言类。可以不配置这项 <ode>dbms</ode> 数据库类型,插件支持的数据库 * <code>sqlPattern</code> 需要拦截的SQL ID * * @param p 属性 */ protected void initProperties(Properties p) { Dialect dialect = null; String dbType = Global.getConfig("jdbc.type"); if ("db2".equals(dbType)) { dialect = new DB2Dialect(); } else if ("derby".equals(dbType)) { dialect = new DerbyDialect(); } else if ("h2".equals(dbType)) { dialect = new H2Dialect(); } else if ("hsql".equals(dbType)) { dialect = new HSQLDialect(); } else if ("mysql".equals(dbType)) { dialect = new MySQLDialect(); } else if ("oracle".equals(dbType)) { dialect = new OracleDialect(); } else if ("postgre".equals(dbType)) { dialect = new PostgreSQLDialect(); } else if ("mssql".equals(dbType) || "sqlserver".equals(dbType)) { dialect = new SQLServer2005Dialect(); } else if ("sybase".equals(dbType)) { dialect = new SybaseDialect(); } if (dialect == null) { throw new RuntimeException("mybatis dialect error."); } DIALECT = dialect; // _SQL_PATTERN = p.getProperty("sqlPattern"); // _SQL_PATTERN = Global.getConfig("mybatis.pagePattern"); // if (StringUtils.isEmpty(_SQL_PATTERN)) { // throw new RuntimeException("sqlPattern property is not found!"); // } } }
/** * This is a simple, synchronous, thread-safe database connection pool. * * @author Clinton Begin */ public class PooledDataSource implements DataSource { private static final Log log = LogFactory.getLog(PooledDataSource.class); private final PoolState state = new PoolState(this); // state保存了空闲连接list和活动连接list private final UnpooledDataSource dataSource; // 组合一个 没pool的数据源 // OPTIONAL CONFIGURATION FIELDS protected int poolMaximumActiveConnections = 10; protected int poolMaximumIdleConnections = 5; protected int poolMaximumCheckoutTime = 20000; // hama protected int poolTimeToWait = 20000; protected String poolPingQuery = "NO PING QUERY SET"; protected boolean poolPingEnabled = false; // hama protected int poolPingConnectionsNotUsedFor = 0; // hama private int expectedConnectionTypeCode; // hama public PooledDataSource() { dataSource = new UnpooledDataSource(); } public PooledDataSource(UnpooledDataSource dataSource) { this.dataSource = dataSource; } public PooledDataSource(String driver, String url, String username, String password) { dataSource = new UnpooledDataSource(driver, url, username, password); expectedConnectionTypeCode = assembleConnectionTypeCode( dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword()); } public PooledDataSource(String driver, String url, Properties driverProperties) { dataSource = new UnpooledDataSource(driver, url, driverProperties); expectedConnectionTypeCode = assembleConnectionTypeCode( dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword()); } public PooledDataSource( ClassLoader driverClassLoader, String driver, String url, String username, String password) { dataSource = new UnpooledDataSource(driverClassLoader, driver, url, username, password); expectedConnectionTypeCode = assembleConnectionTypeCode( dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword()); } public PooledDataSource( ClassLoader driverClassLoader, String driver, String url, Properties driverProperties) { dataSource = new UnpooledDataSource(driverClassLoader, driver, url, driverProperties); expectedConnectionTypeCode = assembleConnectionTypeCode( dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword()); } @Override public Connection getConnection() throws SQLException { // 获得连接,即popConnection(...).getProxyConnection()获得代理连接 return popConnection(dataSource.getUsername(), dataSource.getPassword()).getProxyConnection(); } @Override public Connection getConnection(String username, String password) throws SQLException { return popConnection(username, password).getProxyConnection(); } @Override public void setLoginTimeout(int loginTimeout) throws SQLException { DriverManager.setLoginTimeout(loginTimeout); } @Override public int getLoginTimeout() throws SQLException { return DriverManager.getLoginTimeout(); } @Override public void setLogWriter(PrintWriter logWriter) throws SQLException { DriverManager.setLogWriter(logWriter); } @Override public PrintWriter getLogWriter() throws SQLException { return DriverManager.getLogWriter(); } public void setDriver(String driver) { dataSource.setDriver(driver); forceCloseAll(); } public void setUrl(String url) { dataSource.setUrl(url); forceCloseAll(); } public void setUsername(String username) { dataSource.setUsername(username); forceCloseAll(); } public void setPassword(String password) { dataSource.setPassword(password); forceCloseAll(); } public void setDefaultAutoCommit(boolean defaultAutoCommit) { dataSource.setAutoCommit(defaultAutoCommit); forceCloseAll(); } public void setDefaultTransactionIsolationLevel(Integer defaultTransactionIsolationLevel) { dataSource.setDefaultTransactionIsolationLevel(defaultTransactionIsolationLevel); forceCloseAll(); } public void setDriverProperties(Properties driverProps) { dataSource.setDriverProperties(driverProps); forceCloseAll(); } /* * The maximum number of active connections * * @param poolMaximumActiveConnections The maximum number of active connections */ public void setPoolMaximumActiveConnections(int poolMaximumActiveConnections) { this.poolMaximumActiveConnections = poolMaximumActiveConnections; forceCloseAll(); } /* * The maximum number of idle connections * * @param poolMaximumIdleConnections The maximum number of idle connections */ public void setPoolMaximumIdleConnections(int poolMaximumIdleConnections) { this.poolMaximumIdleConnections = poolMaximumIdleConnections; forceCloseAll(); } /* * The maximum time a connection can be used before it *may* be * given away again. * * @param poolMaximumCheckoutTime The maximum time */ public void setPoolMaximumCheckoutTime(int poolMaximumCheckoutTime) { // 最长的可用时间,check out前能用多久 this.poolMaximumCheckoutTime = poolMaximumCheckoutTime; forceCloseAll(); } /* * The time to wait before retrying to get a connection * * @param poolTimeToWait The time to wait */ public void setPoolTimeToWait(int poolTimeToWait) { // 重试获得连接前的等待时间 this.poolTimeToWait = poolTimeToWait; forceCloseAll(); } /* * The query to be used to check a connection * * @param poolPingQuery The query */ public void setPoolPingQuery(String poolPingQuery) { // hama this.poolPingQuery = poolPingQuery; forceCloseAll(); } /* * Determines if the ping query should be used. * * @param poolPingEnabled True if we need to check a connection before using it */ public void setPoolPingEnabled(boolean poolPingEnabled) { this.poolPingEnabled = poolPingEnabled; forceCloseAll(); } /* * If a connection has not been used in this many milliseconds, ping the * database to make sure the connection is still good. * * @param milliseconds the number of milliseconds of inactivity that will trigger a ping */ public void setPoolPingConnectionsNotUsedFor(int milliseconds) { this.poolPingConnectionsNotUsedFor = milliseconds; forceCloseAll(); } public String getDriver() { return dataSource.getDriver(); } public String getUrl() { return dataSource.getUrl(); } public String getUsername() { return dataSource.getUsername(); } public String getPassword() { return dataSource.getPassword(); } public boolean isAutoCommit() { return dataSource.isAutoCommit(); } public Integer getDefaultTransactionIsolationLevel() { return dataSource.getDefaultTransactionIsolationLevel(); } public Properties getDriverProperties() { return dataSource.getDriverProperties(); } public int getPoolMaximumActiveConnections() { return poolMaximumActiveConnections; } public int getPoolMaximumIdleConnections() { return poolMaximumIdleConnections; } public int getPoolMaximumCheckoutTime() { return poolMaximumCheckoutTime; } public int getPoolTimeToWait() { return poolTimeToWait; } public String getPoolPingQuery() { return poolPingQuery; } public boolean isPoolPingEnabled() { return poolPingEnabled; } public int getPoolPingConnectionsNotUsedFor() { return poolPingConnectionsNotUsedFor; } /* * Closes all active and idle connections in the pool */ public void forceCloseAll() { // 关闭pool里的所有连接,两个list中的连接都移除且关闭 synchronized (state) { expectedConnectionTypeCode = assembleConnectionTypeCode( dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword()); for (int i = state.activeConnections.size(); i > 0; i--) { // 遍历活动连接list try { PooledConnection conn = state.activeConnections.remove(i - 1); // 从活动连接list移出 conn.invalidate(); // PooledConnection的valid设为false Connection realConn = conn.getRealConnection(); // 获取真conn (java.sql.Connection) if (!realConn.getAutoCommit()) { // 不是自动提交的话 realConn.rollback(); // 回滚 } realConn.close(); } catch (Exception e) { // ignore } } for (int i = state.idleConnections.size(); i > 0; i--) { // 简历空闲连接list try { PooledConnection conn = state.idleConnections.remove(i - 1); conn.invalidate(); Connection realConn = conn.getRealConnection(); if (!realConn.getAutoCommit()) { realConn.rollback(); } realConn.close(); } catch (Exception e) { // ignore } } } if (log.isDebugEnabled()) { log.debug("PooledDataSource forcefully closed/removed all connections."); } } public PoolState getPoolState() { return state; } private int assembleConnectionTypeCode(String url, String username, String password) { return ("" + url + username + password).hashCode(); } protected void pushConnection(PooledConnection conn) throws SQLException { // 关闭一个连接,其实是放回pool synchronized (state) { // 加锁 state.activeConnections.remove(conn); // 从活动list移出 if (conn.isValid()) { // conn是有效的 if (state.idleConnections.size() < poolMaximumIdleConnections && conn.getConnectionTypeCode() == expectedConnectionTypeCode) { state.accumulatedCheckoutTime += conn.getCheckoutTime(); if (!conn.getRealConnection().getAutoCommit()) { // 不是自动提交的话 conn.getRealConnection().rollback(); // 回滚 } PooledConnection newConn = new PooledConnection(conn.getRealConnection(), this); // 新建一个连接,用原来的真连接 state.idleConnections.add(newConn); // 加入空闲list newConn.setCreatedTimestamp(conn.getCreatedTimestamp()); newConn.setLastUsedTimestamp(conn.getLastUsedTimestamp()); conn.invalidate(); // 老连接标记为无效 if (log.isDebugEnabled()) { log.debug("Returned connection " + newConn.getRealHashCode() + " to pool."); } state.notifyAll(); // 唤醒popConnection中等待连接的线程可以来抢state的锁 } else { state.accumulatedCheckoutTime += conn.getCheckoutTime(); if (!conn.getRealConnection().getAutoCommit()) { conn.getRealConnection().rollback(); // 回滚 } conn.getRealConnection().close(); // 关闭 if (log.isDebugEnabled()) { log.debug("Closed connection " + conn.getRealHashCode() + "."); } conn.invalidate(); } } else { if (log.isDebugEnabled()) { log.debug( "A bad connection (" + conn.getRealHashCode() + ") attempted to return to the pool, discarding connection."); } state.badConnectionCount++; } } } private PooledConnection popConnection(String username, String password) throws SQLException { // 获取一个连接 boolean countedWait = false; PooledConnection conn = null; long t = System.currentTimeMillis(); int localBadConnectionCount = 0; while (conn == null) { synchronized (state) { if (!state.idleConnections.isEmpty()) { // pool里还有空闲连接 // Pool has available connection conn = state.idleConnections.remove(0); // 从空闲list移出一个conn,用做新连接 if (log.isDebugEnabled()) { log.debug("Checked out connection " + conn.getRealHashCode() + " from pool."); } } else { // pool里没有空闲连接了 // Pool does not have available connection if (state.activeConnections.size() < poolMaximumActiveConnections) { // 活动list没有满 // Can create new connection conn = new PooledConnection(dataSource.getConnection(), this); // 新建一个PooledConnection if (log.isDebugEnabled()) { log.debug("Created connection " + conn.getRealHashCode() + "."); } } else { // 活动list已经满了,无法创建新连接 // Cannot create new connection PooledConnection oldestActiveConnection = state.activeConnections.get(0); // 获取最早开始活动的连接 long longestCheckoutTime = oldestActiveConnection.getCheckoutTime(); // 获得最老的活动连接的checkout时间 if (longestCheckoutTime > poolMaximumCheckoutTime) { // 如果checkout时间大于最大值 // Can claim overdue connection state.claimedOverdueConnectionCount++; // 过期连接计数++ state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime; // 累加过期连接的checkout时间 state.accumulatedCheckoutTime += longestCheckoutTime; // 累加checkout时间 state.activeConnections.remove(oldestActiveConnection); // 从活动list移出最老的活动连接,留出空位来啦 if (!oldestActiveConnection.getRealConnection().getAutoCommit()) { oldestActiveConnection.getRealConnection().rollback(); // 回滚 } conn = new PooledConnection( oldestActiveConnection.getRealConnection(), this); // 新建连接,用最老连接的真连接 oldestActiveConnection.invalidate(); // 最老连接标记无效 if (log.isDebugEnabled()) { log.debug("Claimed overdue connection " + conn.getRealHashCode() + "."); } } else { // 如果checkout时间并没有超过最大值,必须等待 // Must wait try { if (!countedWait) { // countedWait原来是false state.hadToWaitCount++; // 必须等待的计数++ countedWait = true; // countedWait变为true } if (log.isDebugEnabled()) { log.debug( "Waiting as long as " + poolTimeToWait + " milliseconds for connection."); } long wt = System.currentTimeMillis(); state.wait( poolTimeToWait); // 等poolTimeToWait微秒,pushConnection移出一个连接时会notifyAll来唤醒wait的线程 state.accumulatedWaitTime += System.currentTimeMillis() - wt; } catch (InterruptedException e) { break; } } } } if (conn != null) { // conn非空,确实建出来了 if (conn.isValid()) { // conn有效 if (!conn.getRealConnection().getAutoCommit()) { conn.getRealConnection().rollback(); // 这里回滚是干啥? hama } conn.setConnectionTypeCode( assembleConnectionTypeCode(dataSource.getUrl(), username, password)); conn.setCheckoutTimestamp(System.currentTimeMillis()); conn.setLastUsedTimestamp(System.currentTimeMillis()); state.activeConnections.add(conn); // 加入活动list state.requestCount++; state.accumulatedRequestTime += System.currentTimeMillis() - t; } else { // conn无效 if (log.isDebugEnabled()) { log.debug( "A bad connection (" + conn.getRealHashCode() + ") was returned from the pool, getting another connection."); } state.badConnectionCount++; localBadConnectionCount++; conn = null; if (localBadConnectionCount > (poolMaximumIdleConnections + 3)) { if (log.isDebugEnabled()) { log.debug("PooledDataSource: Could not get a good connection to the database."); } throw new SQLException( "PooledDataSource: Could not get a good connection to the database."); } } } } } // 到这里while结束 if (conn == null) { // 出现了奇葩的Unknown错吧 if (log.isDebugEnabled()) { log.debug( "PooledDataSource: Unknown severe error condition. The connection pool returned a null connection."); } throw new SQLException( "PooledDataSource: Unknown severe error condition. The connection pool returned a null connection."); } return conn; } /* * Method to check to see if a connection is still usable * * @param conn - the connection to check * @return True if the connection is still usable */ protected boolean pingConnection(PooledConnection conn) { // 用连接做个查询,测试一个 boolean result = true; try { result = !conn.getRealConnection().isClosed(); } catch (SQLException e) { if (log.isDebugEnabled()) { log.debug("Connection " + conn.getRealHashCode() + " is BAD: " + e.getMessage()); } result = false; } if (result) { if (poolPingEnabled) { if (poolPingConnectionsNotUsedFor >= 0 && conn.getTimeElapsedSinceLastUse() > poolPingConnectionsNotUsedFor) { try { if (log.isDebugEnabled()) { log.debug("Testing connection " + conn.getRealHashCode() + " ..."); } Connection realConn = conn.getRealConnection(); // 取出真连接 Statement statement = realConn.createStatement(); ResultSet rs = statement.executeQuery(poolPingQuery); // 测试一个 rs.close(); statement.close(); if (!realConn.getAutoCommit()) { realConn.rollback(); } result = true; if (log.isDebugEnabled()) { log.debug("Connection " + conn.getRealHashCode() + " is GOOD!"); } } catch (Exception e) { log.warn("Execution of ping query '" + poolPingQuery + "' failed: " + e.getMessage()); try { conn.getRealConnection().close(); } catch (Exception e2) { // ignore } result = false; if (log.isDebugEnabled()) { log.debug("Connection " + conn.getRealHashCode() + " is BAD: " + e.getMessage()); } } } } } return result; } /* * Unwraps a pooled connection to get to the 'real' connection * * @param conn - the pooled connection to unwrap * @return The 'real' connection */ public static Connection unwrapConnection(Connection conn) { if (Proxy.isProxyClass(conn.getClass())) { InvocationHandler handler = Proxy.getInvocationHandler(conn); if (handler instanceof PooledConnection) { return ((PooledConnection) handler).getRealConnection(); } } return conn; } protected void finalize() throws Throwable { // 被GC前挣扎一记的finalize forceCloseAll(); // 全关了 super.finalize(); } public <T> T unwrap(Class<T> iface) throws SQLException { throw new SQLException(getClass().getName() + " is not a wrapper."); } public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; } public Logger getParentLogger() { return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); // requires JDK version 1.6 } }
public MyBatis start() { LogFactory.useSlf4jLogging(); Configuration conf = new Configuration(); conf.setEnvironment( new Environment("production", createTransactionFactory(), database.getDataSource())); conf.setUseGeneratedKeys(true); conf.setLazyLoadingEnabled(false); conf.setJdbcTypeForNull(JdbcType.NULL); Dialect dialect = database.getDialect(); conf.setDatabaseId(dialect.getId()); conf.getVariables().setProperty("_true", dialect.getTrueSqlValue()); conf.getVariables().setProperty("_false", dialect.getFalseSqlValue()); conf.getVariables() .setProperty("_scrollFetchSize", String.valueOf(dialect.getScrollDefaultFetchSize())); loadAlias(conf, "ActiveDashboard", ActiveDashboardDto.class); loadAlias(conf, "Author", AuthorDto.class); loadAlias(conf, "Component", ComponentDto.class); loadAlias(conf, "Dashboard", DashboardDto.class); loadAlias(conf, "Dependency", DependencyDto.class); loadAlias(conf, "DuplicationUnit", DuplicationUnitDto.class); loadAlias(conf, "Graph", GraphDto.class); loadAlias(conf, "Group", GroupDto.class); loadAlias(conf, "GroupRole", GroupRoleDto.class); loadAlias(conf, "GroupMembership", GroupMembershipDto.class); loadAlias(conf, "LoadedTemplate", LoadedTemplateDto.class); loadAlias(conf, "MeasureFilter", MeasureFilterDto.class); loadAlias(conf, "NotificationQueue", NotificationQueueDto.class); loadAlias(conf, "Property", PropertyDto.class); loadAlias(conf, "PurgeableSnapshot", PurgeableSnapshotDto.class); loadAlias(conf, "QualityGate", QualityGateDto.class); loadAlias(conf, "QualityGateCondition", QualityGateConditionDto.class); loadAlias(conf, "ProjectQgateAssociation", ProjectQgateAssociationDto.class); loadAlias(conf, "Resource", ResourceDto.class); loadAlias(conf, "ResourceIndex", ResourceIndexDto.class); loadAlias(conf, "ResourceSnapshot", ResourceSnapshotDto.class); loadAlias(conf, "Rule", RuleDto.class); loadAlias(conf, "RuleParam", RuleParamDto.class); loadAlias(conf, "Snapshot", SnapshotDto.class); loadAlias(conf, "Semaphore", SemaphoreDto.class); loadAlias(conf, "SchemaMigration", SchemaMigrationDto.class); loadAlias(conf, "User", UserDto.class); loadAlias(conf, "UserRole", UserRoleDto.class); loadAlias(conf, "UserGroup", UserGroupDto.class); loadAlias(conf, "Widget", WidgetDto.class); loadAlias(conf, "WidgetProperty", WidgetPropertyDto.class); loadAlias(conf, "MeasureModel", MeasureModel.class); loadAlias(conf, "Measure", MeasureDto.class); loadAlias(conf, "Metric", MetricDto.class); loadAlias(conf, "Issue", IssueDto.class); loadAlias(conf, "IssueChange", IssueChangeDto.class); loadAlias(conf, "IssueFilter", IssueFilterDto.class); loadAlias(conf, "IssueFilterFavourite", IssueFilterFavouriteDto.class); loadAlias(conf, "ActionPlanIssue", ActionPlanDto.class); loadAlias(conf, "ActionPlanStats", ActionPlanStatsDto.class); loadAlias(conf, "PermissionTemplate", PermissionTemplateDto.class); loadAlias(conf, "PermissionTemplateUser", PermissionTemplateUserDto.class); loadAlias(conf, "PermissionTemplateGroup", PermissionTemplateGroupDto.class); loadAlias(conf, "Characteristic", CharacteristicDto.class); loadAlias(conf, "UserWithPermission", UserWithPermissionDto.class); loadAlias(conf, "GroupWithPermission", GroupWithPermissionDto.class); loadAlias(conf, "QualityProfile", QualityProfileDto.class); loadAlias(conf, "ActiveRule", ActiveRuleDto.class); loadAlias(conf, "ActiveRuleParam", ActiveRuleParamDto.class); loadAlias(conf, "RequirementMigration", RequirementMigrationDto.class); loadAlias(conf, "Activity", ActivityDto.class); loadAlias(conf, "AnalysisReport", AnalysisReportDto.class); loadAlias(conf, "IdUuidPair", IdUuidPair.class); loadAlias(conf, "FilePathWithHash", FilePathWithHashDto.class); loadAlias(conf, "UuidWithProjectUuid", UuidWithProjectUuidDto.class); // AuthorizationMapper has to be loaded before IssueMapper because this last one used it loadMapper(conf, "org.sonar.core.user.AuthorizationMapper"); // ResourceMapper has to be loaded before IssueMapper because this last one used it loadMapper(conf, ResourceMapper.class); loadMapper(conf, "org.sonar.core.permission.PermissionMapper"); Class<?>[] mappers = { ActivityMapper.class, ActiveDashboardMapper.class, AuthorMapper.class, DashboardMapper.class, DependencyMapper.class, DuplicationMapper.class, GraphDtoMapper.class, IssueMapper.class, IssueChangeMapper.class, IssueFilterMapper.class, IssueFilterFavouriteMapper.class, LoadedTemplateMapper.class, MeasureFilterMapper.class, Migration44Mapper.class, PermissionTemplateMapper.class, PropertiesMapper.class, PurgeMapper.class, ResourceKeyUpdaterMapper.class, ResourceIndexerMapper.class, ResourceSnapshotMapper.class, RoleMapper.class, RuleMapper.class, SchemaMigrationMapper.class, SemaphoreMapper.class, UserMapper.class, GroupMapper.class, UserGroupMapper.class, WidgetMapper.class, WidgetPropertyMapper.class, org.sonar.api.database.model.MeasureMapper.class, FileSourceMapper.class, ActionPlanMapper.class, ActionPlanStatsMapper.class, NotificationQueueMapper.class, CharacteristicMapper.class, GroupMembershipMapper.class, QualityProfileMapper.class, ActiveRuleMapper.class, MeasureMapper.class, MetricMapper.class, QualityGateMapper.class, QualityGateConditionMapper.class, ComponentMapper.class, SnapshotMapper.class, ProjectQgateAssociationMapper.class, AnalysisReportMapper.class, ComponentIndexMapper.class, Migration45Mapper.class, Migration50Mapper.class }; loadMappers(conf, mappers); sessionFactory = new SqlSessionFactoryBuilder().build(conf); return this; }
public abstract class BaseExecutor implements Executor { private static final Log log = LogFactory.getLog(BaseExecutor.class); // for backward compatibility with 3.0 style logging private static final Log connectionLog = LogFactory.getLog(Connection.class); protected Transaction transaction; protected ConcurrentLinkedQueue<DeferredLoad> deferredLoads; protected PerpetualCache localCache; protected PerpetualCache localOutputParameterCache; protected Configuration configuration; protected int queryStack = 0; protected List<BatchResult> batchResults = new ArrayList<BatchResult>(); private boolean closed; protected BaseExecutor(Configuration configuration, Transaction transaction) { this.transaction = transaction; this.deferredLoads = new ConcurrentLinkedQueue<DeferredLoad>(); this.localCache = new PerpetualCache("LocalCache"); this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache"); this.closed = false; this.configuration = configuration; } public Transaction getTransaction() { if (closed) throw new ExecutorException("Executor was closed."); return transaction; } public void close(boolean forceRollback) { try { try { rollback(forceRollback); } finally { if (transaction != null) transaction.close(); } } catch (SQLException e) { // Ignore. There's nothing that can be done at this point. log.debug("Unexpected exception on closing transaction. Cause: " + e); } finally { transaction = null; deferredLoads = null; localCache = null; localOutputParameterCache = null; batchResults = null; closed = true; } } public boolean isClosed() { return closed; } public int update(MappedStatement ms, Object parameter) throws SQLException { ErrorContext.instance() .resource(ms.getResource()) .activity("executing an update") .object(ms.getId()); if (closed) throw new ExecutorException("Executor was closed."); clearLocalCache(); return doUpdate(ms, parameter); } public List<BatchResult> flushStatements() throws SQLException { return flushStatements(false); } public List<BatchResult> flushStatements(boolean isRollBack) throws SQLException { if (closed) throw new ExecutorException("Executor was closed."); batchResults.addAll(doFlushStatements(isRollBack)); return batchResults; } public <E> List<E> query( MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { BoundSql boundSql = ms.getBoundSql(parameter); CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql); return query(ms, parameter, rowBounds, resultHandler, key, boundSql); } @SuppressWarnings("unchecked") public <E> List<E> query( MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { ErrorContext.instance() .resource(ms.getResource()) .activity("executing a query") .object(ms.getId()); if (closed) throw new ExecutorException("Executor was closed."); if (queryStack == 0 && ms.isFlushCacheRequired()) { clearLocalCache(); } List<E> list; try { queryStack++; list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; if (list != null) { handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } finally { queryStack--; } if (queryStack == 0) { for (DeferredLoad deferredLoad : deferredLoads) { deferredLoad.load(); } if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { clearLocalCache(); // issue #482 } } return list; } public void deferLoad( MappedStatement ms, MetaObject resultObject, String property, CacheKey key) { if (closed) throw new ExecutorException("Executor was closed."); DeferredLoad deferredLoad = new DeferredLoad(ms, resultObject, property, key, localCache, configuration); if (deferredLoad.canLoad()) { deferredLoad.load(); } else { deferredLoads.add( new DeferredLoad(ms, resultObject, property, key, localCache, configuration)); } } public CacheKey createCacheKey( MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) { if (closed) throw new ExecutorException("Executor was closed."); CacheKey cacheKey = new CacheKey(); cacheKey.update(ms.getId()); cacheKey.update(rowBounds.getOffset()); cacheKey.update(rowBounds.getLimit()); cacheKey.update(boundSql.getSql()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings.size() > 0 && parameterObject != null) { TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry(); if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { cacheKey.update(parameterObject); } else { MetaObject metaObject = configuration.newMetaObject(parameterObject); for (ParameterMapping parameterMapping : parameterMappings) { String propertyName = parameterMapping.getProperty(); if (metaObject.hasGetter(propertyName)) { cacheKey.update(metaObject.getValue(propertyName)); } else if (boundSql.hasAdditionalParameter(propertyName)) { cacheKey.update(boundSql.getAdditionalParameter(propertyName)); } } } } return cacheKey; } public boolean isCached(MappedStatement ms, CacheKey key) { return localCache.getObject(key) != null; } public void commit(boolean required) throws SQLException { if (closed) throw new ExecutorException("Cannot commit, transaction is already closed"); clearLocalCache(); flushStatements(); if (required) { transaction.commit(); } } public void rollback(boolean required) throws SQLException { if (!closed) { try { clearLocalCache(); flushStatements(true); } finally { if (required) { transaction.rollback(); } } } } public void clearLocalCache() { if (!closed) { localCache.clear(); localOutputParameterCache.clear(); } } protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException; protected abstract List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException; protected abstract <E> List<E> doQuery( MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException; protected void closeStatement(Statement statement) { if (statement != null) { try { statement.close(); } catch (SQLException e) { // ignore } } } private void handleLocallyCachedOutputParameters( MappedStatement ms, CacheKey key, Object parameter, BoundSql boundSql) { if (ms.getStatementType() == StatementType.CALLABLE) { final Object cachedParameter = localOutputParameterCache.getObject(key); if (cachedParameter != null && parameter != null) { final MetaObject metaCachedParameter = MetaObject.forObject(cachedParameter); final MetaObject metaParameter = MetaObject.forObject(parameter); for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) { if (parameterMapping.getMode() != ParameterMode.IN) { final String parameterName = parameterMapping.getProperty(); final Object cachedValue = metaCachedParameter.getValue(parameterName); metaParameter.setValue(parameterName, cachedValue); } } } } } private <E> List<E> queryFromDatabase( MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List<E> list; localCache.putObject(key, EXECUTION_PLACEHOLDER); try { list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); } finally { localCache.removeObject(key); } localCache.putObject(key, list); if (ms.getStatementType() == StatementType.CALLABLE) { localOutputParameterCache.putObject(key, parameter); } return list; } protected Connection getConnection(Log statementLog) throws SQLException { Connection connection = transaction.getConnection(); if (statementLog.isDebugEnabled() || connectionLog.isDebugEnabled()) { return ConnectionLogger.newInstance(connection, statementLog); } else { return connection; } } private static class DeferredLoad { private final MetaObject resultObject; private final String property; private final CacheKey key; private final PerpetualCache localCache; private final ObjectFactory objectFactory; private final Configuration configuration; public DeferredLoad( MappedStatement mappedStatement, MetaObject resultObject, String property, CacheKey key, PerpetualCache localCache, Configuration configuration) { this.resultObject = resultObject; this.property = property; this.key = key; this.localCache = localCache; this.objectFactory = configuration.getObjectFactory(); this.configuration = configuration; } public boolean canLoad() { return localCache.getObject(key) != null && localCache.getObject(key) != EXECUTION_PLACEHOLDER; } public void load() { Object value = null; @SuppressWarnings("unchecked") // we suppose we get back a List List<Object> list = (List<Object>) localCache.getObject(key); Class<?> targetType = resultObject.getSetterType(property); if (targetType.isAssignableFrom(list.getClass())) { value = list; } else if (objectFactory.isCollection(targetType)) { value = objectFactory.create(targetType); MetaObject metaObject = configuration.newMetaObject(value); metaObject.addAll(list); } else if (targetType.isArray()) { Object[] array = (Object[]) Array.newInstance(targetType.getComponentType(), list.size()); value = list.toArray(array); } else { if (list != null && list.size() > 1) { throw new ExecutorException( "Statement returned more than one row, where no more than one was expected."); } else if (list != null && list.size() == 1) { value = list.get(0); } } resultObject.setValue(property, value); } } }
/* * This is a simple, synchronous, thread-safe database connection pool. */ public class PooledDataSource implements DataSource { private static final Log log = LogFactory.getLog(PooledDataSource.class); private final PoolState state = new PoolState(this); private final UnpooledDataSource dataSource; // OPTIONAL CONFIGURATION FIELDS protected int poolMaximumActiveConnections = 10; protected int poolMaximumIdleConnections = 5; protected int poolMaximumCheckoutTime = 20000; protected int poolTimeToWait = 20000; protected String poolPingQuery = "NO PING QUERY SET"; protected boolean poolPingEnabled = false; protected int poolPingConnectionsNotUsedFor = 0; private int expectedConnectionTypeCode; public PooledDataSource() { dataSource = new UnpooledDataSource(); } public PooledDataSource(String driver, String url, String username, String password) { dataSource = new UnpooledDataSource(driver, url, username, password); expectedConnectionTypeCode = assembleConnectionTypeCode( dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword()); } public PooledDataSource(String driver, String url, Properties driverProperties) { dataSource = new UnpooledDataSource(driver, url, driverProperties); expectedConnectionTypeCode = assembleConnectionTypeCode( dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword()); } public PooledDataSource( ClassLoader driverClassLoader, String driver, String url, String username, String password) { dataSource = new UnpooledDataSource(driverClassLoader, driver, url, username, password); expectedConnectionTypeCode = assembleConnectionTypeCode( dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword()); } public PooledDataSource( ClassLoader driverClassLoader, String driver, String url, Properties driverProperties) { dataSource = new UnpooledDataSource(driverClassLoader, driver, url, driverProperties); expectedConnectionTypeCode = assembleConnectionTypeCode( dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword()); } public Connection getConnection() throws SQLException { return popConnection(dataSource.getUsername(), dataSource.getPassword()).getProxyConnection(); } public Connection getConnection(String username, String password) throws SQLException { return popConnection(username, password).getProxyConnection(); } public void setLoginTimeout(int loginTimeout) throws SQLException { DriverManager.setLoginTimeout(loginTimeout); } public int getLoginTimeout() throws SQLException { return DriverManager.getLoginTimeout(); } public void setLogWriter(PrintWriter logWriter) throws SQLException { DriverManager.setLogWriter(logWriter); } public PrintWriter getLogWriter() throws SQLException { return DriverManager.getLogWriter(); } public void setDriver(String driver) { dataSource.setDriver(driver); forceCloseAll(); } public void setUrl(String url) { dataSource.setUrl(url); forceCloseAll(); } public void setUsername(String username) { dataSource.setUsername(username); forceCloseAll(); } public void setPassword(String password) { dataSource.setPassword(password); forceCloseAll(); } public void setDefaultAutoCommit(boolean defaultAutoCommit) { dataSource.setAutoCommit(defaultAutoCommit); forceCloseAll(); } public void setDefaultTransactionIsolationLevel(Integer defaultTransactionIsolationLevel) { dataSource.setDefaultTransactionIsolationLevel(defaultTransactionIsolationLevel); forceCloseAll(); } public void setDriverProperties(Properties driverProps) { dataSource.setDriverProperties(driverProps); forceCloseAll(); } /* * The maximum number of active connections * * @param poolMaximumActiveConnections The maximum number of active connections */ public void setPoolMaximumActiveConnections(int poolMaximumActiveConnections) { this.poolMaximumActiveConnections = poolMaximumActiveConnections; forceCloseAll(); } /* * The maximum number of idle connections * * @param poolMaximumIdleConnections The maximum number of idle connections */ public void setPoolMaximumIdleConnections(int poolMaximumIdleConnections) { this.poolMaximumIdleConnections = poolMaximumIdleConnections; forceCloseAll(); } /* * The maximum time a connection can be used before it *may* be * given away again. * * @param poolMaximumCheckoutTime The maximum time */ public void setPoolMaximumCheckoutTime(int poolMaximumCheckoutTime) { this.poolMaximumCheckoutTime = poolMaximumCheckoutTime; forceCloseAll(); } /* * The time to wait before retrying to get a connection * * @param poolTimeToWait The time to wait */ public void setPoolTimeToWait(int poolTimeToWait) { this.poolTimeToWait = poolTimeToWait; forceCloseAll(); } /* * The query to be used to check a connection * * @param poolPingQuery The query */ public void setPoolPingQuery(String poolPingQuery) { this.poolPingQuery = poolPingQuery; forceCloseAll(); } /* * Determines if the ping query should be used. * * @param poolPingEnabled True if we need to check a connection before using it */ public void setPoolPingEnabled(boolean poolPingEnabled) { this.poolPingEnabled = poolPingEnabled; forceCloseAll(); } /* * If a connection has not been used in this many milliseconds, ping the * database to make sure the connection is still good. * * @param milliseconds the number of milliseconds of inactivity that will trigger a ping */ public void setPoolPingConnectionsNotUsedFor(int milliseconds) { this.poolPingConnectionsNotUsedFor = milliseconds; forceCloseAll(); } public String getDriver() { return dataSource.getDriver(); } public String getUrl() { return dataSource.getUrl(); } public String getUsername() { return dataSource.getUsername(); } public String getPassword() { return dataSource.getPassword(); } public boolean isAutoCommit() { return dataSource.isAutoCommit(); } public Integer getDefaultTransactionIsolationLevel() { return dataSource.getDefaultTransactionIsolationLevel(); } public Properties getDriverProperties() { return dataSource.getDriverProperties(); } public int getPoolMaximumActiveConnections() { return poolMaximumActiveConnections; } public int getPoolMaximumIdleConnections() { return poolMaximumIdleConnections; } public int getPoolMaximumCheckoutTime() { return poolMaximumCheckoutTime; } public int getPoolTimeToWait() { return poolTimeToWait; } public String getPoolPingQuery() { return poolPingQuery; } public boolean isPoolPingEnabled() { return poolPingEnabled; } public int getPoolPingConnectionsNotUsedFor() { return poolPingConnectionsNotUsedFor; } /* * Closes all active and idle connections in the pool */ public void forceCloseAll() { synchronized (state) { expectedConnectionTypeCode = assembleConnectionTypeCode( dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword()); for (int i = state.activeConnections.size(); i > 0; i--) { try { PooledConnection conn = (PooledConnection) state.activeConnections.remove(i - 1); conn.invalidate(); Connection realConn = conn.getRealConnection(); if (!realConn.getAutoCommit()) { realConn.rollback(); } realConn.close(); } catch (Exception e) { // ignore } } for (int i = state.idleConnections.size(); i > 0; i--) { try { PooledConnection conn = (PooledConnection) state.idleConnections.remove(i - 1); conn.invalidate(); Connection realConn = conn.getRealConnection(); if (!realConn.getAutoCommit()) { realConn.rollback(); } realConn.close(); } catch (Exception e) { // ignore } } } if (log.isDebugEnabled()) { log.debug("PooledDataSource forcefully closed/removed all connections."); } } public PoolState getPoolState() { return state; } private int assembleConnectionTypeCode(String url, String username, String password) { return ("" + url + username + password).hashCode(); } protected void pushConnection(PooledConnection conn) throws SQLException { synchronized (state) { state.activeConnections.remove(conn); if (conn.isValid()) { if (state.idleConnections.size() < poolMaximumIdleConnections && conn.getConnectionTypeCode() == expectedConnectionTypeCode) { state.accumulatedCheckoutTime += conn.getCheckoutTime(); if (!conn.getRealConnection().getAutoCommit()) { conn.getRealConnection().rollback(); } PooledConnection newConn = new PooledConnection(conn.getRealConnection(), this); state.idleConnections.add(newConn); newConn.setCreatedTimestamp(conn.getCreatedTimestamp()); newConn.setLastUsedTimestamp(conn.getLastUsedTimestamp()); conn.invalidate(); if (log.isDebugEnabled()) { log.debug("Returned connection " + newConn.getRealHashCode() + " to pool."); } state.notifyAll(); } else { state.accumulatedCheckoutTime += conn.getCheckoutTime(); if (!conn.getRealConnection().getAutoCommit()) { conn.getRealConnection().rollback(); } conn.getRealConnection().close(); if (log.isDebugEnabled()) { log.debug("Closed connection " + conn.getRealHashCode() + "."); } conn.invalidate(); } } else { if (log.isDebugEnabled()) { log.debug( "A bad connection (" + conn.getRealHashCode() + ") attempted to return to the pool, discarding connection."); } state.badConnectionCount++; } } } private PooledConnection popConnection(String username, String password) throws SQLException { boolean countedWait = false; PooledConnection conn = null; long t = System.currentTimeMillis(); int localBadConnectionCount = 0; while (conn == null) { synchronized (state) { if (state.idleConnections.size() > 0) { // Pool has available connection conn = (PooledConnection) state.idleConnections.remove(0); if (log.isDebugEnabled()) { log.debug("Checked out connection " + conn.getRealHashCode() + " from pool."); } } else { // Pool does not have available connection if (state.activeConnections.size() < poolMaximumActiveConnections) { // Can create new connection conn = new PooledConnection(dataSource.getConnection(), this); @SuppressWarnings("unused") // used in logging, if enabled Connection realConn = conn.getRealConnection(); if (log.isDebugEnabled()) { log.debug("Created connection " + conn.getRealHashCode() + "."); } } else { // Cannot create new connection PooledConnection oldestActiveConnection = (PooledConnection) state.activeConnections.get(0); long longestCheckoutTime = oldestActiveConnection.getCheckoutTime(); if (longestCheckoutTime > poolMaximumCheckoutTime) { // Can claim overdue connection state.claimedOverdueConnectionCount++; state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime; state.accumulatedCheckoutTime += longestCheckoutTime; state.activeConnections.remove(oldestActiveConnection); if (!oldestActiveConnection.getRealConnection().getAutoCommit()) { oldestActiveConnection.getRealConnection().rollback(); } conn = new PooledConnection(oldestActiveConnection.getRealConnection(), this); oldestActiveConnection.invalidate(); if (log.isDebugEnabled()) { log.debug("Claimed overdue connection " + conn.getRealHashCode() + "."); } } else { // Must wait try { if (!countedWait) { state.hadToWaitCount++; countedWait = true; } if (log.isDebugEnabled()) { log.debug( "Waiting as long as " + poolTimeToWait + " milliseconds for connection."); } long wt = System.currentTimeMillis(); state.wait(poolTimeToWait); state.accumulatedWaitTime += System.currentTimeMillis() - wt; } catch (InterruptedException e) { break; } } } } if (conn != null) { if (conn.isValid()) { if (!conn.getRealConnection().getAutoCommit()) { conn.getRealConnection().rollback(); } conn.setConnectionTypeCode( assembleConnectionTypeCode(dataSource.getUrl(), username, password)); conn.setCheckoutTimestamp(System.currentTimeMillis()); conn.setLastUsedTimestamp(System.currentTimeMillis()); state.activeConnections.add(conn); state.requestCount++; state.accumulatedRequestTime += System.currentTimeMillis() - t; } else { if (log.isDebugEnabled()) { log.debug( "A bad connection (" + conn.getRealHashCode() + ") was returned from the pool, getting another connection."); } state.badConnectionCount++; localBadConnectionCount++; conn = null; if (localBadConnectionCount > (poolMaximumIdleConnections + 3)) { if (log.isDebugEnabled()) { log.debug("PooledDataSource: Could not get a good connection to the database."); } throw new SQLException( "PooledDataSource: Could not get a good connection to the database."); } } } } } if (conn == null) { if (log.isDebugEnabled()) { log.debug( "PooledDataSource: Unknown severe error condition. The connection pool returned a null connection."); } throw new SQLException( "PooledDataSource: Unknown severe error condition. The connection pool returned a null connection."); } return conn; } /* * Method to check to see if a connection is still usable * * @param conn - the connection to check * @return True if the connection is still usable */ protected boolean pingConnection(PooledConnection conn) { boolean result = true; try { result = !conn.getRealConnection().isClosed(); } catch (SQLException e) { if (log.isDebugEnabled()) { log.debug("Connection " + conn.getRealHashCode() + " is BAD: " + e.getMessage()); } result = false; } if (result) { if (poolPingEnabled) { if (poolPingConnectionsNotUsedFor >= 0 && conn.getTimeElapsedSinceLastUse() > poolPingConnectionsNotUsedFor) { try { if (log.isDebugEnabled()) { log.debug("Testing connection " + conn.getRealHashCode() + " ..."); } Connection realConn = conn.getRealConnection(); Statement statement = realConn.createStatement(); ResultSet rs = statement.executeQuery(poolPingQuery); rs.close(); statement.close(); if (!realConn.getAutoCommit()) { realConn.rollback(); } result = true; if (log.isDebugEnabled()) { log.debug("Connection " + conn.getRealHashCode() + " is GOOD!"); } } catch (Exception e) { log.warn("Execution of ping query '" + poolPingQuery + "' failed: " + e.getMessage()); try { conn.getRealConnection().close(); } catch (Exception e2) { // ignore } result = false; if (log.isDebugEnabled()) { log.debug("Connection " + conn.getRealHashCode() + " is BAD: " + e.getMessage()); } } } } } return result; } /* * Unwraps a pooled connection to get to the 'real' connection * * @param conn - the pooled connection to unwrap * @return The 'real' connection */ public static Connection unwrapConnection(Connection conn) { if (Proxy.isProxyClass(conn.getClass())) { InvocationHandler handler = Proxy.getInvocationHandler(conn); if (handler instanceof PooledConnection) { return ((PooledConnection) handler).getRealConnection(); } } return conn; } protected void finalize() throws Throwable { forceCloseAll(); } public <T> T unwrap(Class<T> iface) throws SQLException { throw new SQLException(getClass().getName() + " is not a wrapper."); } public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; } public Logger getParentLogger() { return Logger.getLogger(LogFactory.GLOBAL_LOGGER_NAME); } }
/** @author Clinton Begin */ public class CglibProxyFactory implements ProxyFactory { private static final Log log = LogFactory.getLog(CglibProxyFactory.class); private static final String FINALIZE_METHOD = "finalize"; private static final String WRITE_REPLACE_METHOD = "writeReplace"; public CglibProxyFactory() { try { Resources.classForName("net.sf.cglib.proxy.Enhancer"); } catch (Throwable e) { throw new IllegalStateException( "Cannot enable lazy loading because CGLIB is not available. Add CGLIB to your classpath.", e); } } public Object createProxy( Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) { return EnhancedResultObjectProxyImpl.createProxy( target, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs); } public Object createDeserializationProxy( Object target, Map<String, ResultLoaderMap.LoadPair> unloadedProperties, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) { return EnhancedDeserializationProxyImpl.createProxy( target, unloadedProperties, objectFactory, constructorArgTypes, constructorArgs); } public void setProperties(Properties properties) {} private static Object crateProxy( Class<?> type, Callback callback, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) { Enhancer enhancer = new Enhancer(); enhancer.setCallback(callback); enhancer.setSuperclass(type); try { type.getDeclaredMethod(WRITE_REPLACE_METHOD); // ObjectOutputStream will call writeReplace of objects returned by writeReplace log.debug( WRITE_REPLACE_METHOD + " method was found on bean " + type + ", make sure it returns this"); } catch (NoSuchMethodException e) { enhancer.setInterfaces(new Class[] {WriteReplaceInterface.class}); } catch (SecurityException e) { // nothing to do here } Object enhanced = null; if (constructorArgTypes.isEmpty()) { enhanced = enhancer.create(); } else { Class<?>[] typesArray = constructorArgTypes.toArray(new Class[constructorArgTypes.size()]); Object[] valuesArray = constructorArgs.toArray(new Object[constructorArgs.size()]); enhanced = enhancer.create(typesArray, valuesArray); } return enhanced; } private static class EnhancedResultObjectProxyImpl implements MethodInterceptor { private Class<?> type; private ResultLoaderMap lazyLoader; private boolean aggressive; private Set<String> lazyLoadTriggerMethods; private ObjectFactory objectFactory; private List<Class<?>> constructorArgTypes; private List<Object> constructorArgs; private EnhancedResultObjectProxyImpl( Class<?> type, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) { this.type = type; this.lazyLoader = lazyLoader; this.aggressive = configuration.isAggressiveLazyLoading(); this.lazyLoadTriggerMethods = configuration.getLazyLoadTriggerMethods(); this.objectFactory = objectFactory; this.constructorArgTypes = constructorArgTypes; this.constructorArgs = constructorArgs; } public static Object createProxy( Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) { final Class<?> type = target.getClass(); EnhancedResultObjectProxyImpl callback = new EnhancedResultObjectProxyImpl( type, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs); Object enhanced = crateProxy(type, callback, constructorArgTypes, constructorArgs); PropertyCopier.copyBeanProperties(type, target, enhanced); return enhanced; } public Object intercept(Object enhanced, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { final String methodName = method.getName(); try { synchronized (lazyLoader) { if (WRITE_REPLACE_METHOD.equals(methodName)) { Object original = null; if (constructorArgTypes.isEmpty()) { original = objectFactory.create(type); } else { original = objectFactory.create(type, constructorArgTypes, constructorArgs); } PropertyCopier.copyBeanProperties(type, enhanced, original); if (lazyLoader.size() > 0) { return new CglibSerialStateHolder( original, lazyLoader.getProperties(), objectFactory, constructorArgTypes, constructorArgs); } else { return original; } } else { if (lazyLoader.size() > 0 && !FINALIZE_METHOD.equals(methodName)) { if (aggressive || lazyLoadTriggerMethods.contains(methodName)) { lazyLoader.loadAll(); } else if (PropertyNamer.isProperty(methodName)) { final String property = PropertyNamer.methodToProperty(methodName); if (lazyLoader.hasLoader(property)) { lazyLoader.load(property); } } } } } return methodProxy.invokeSuper(enhanced, args); } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } } } private static class EnhancedDeserializationProxyImpl extends AbstractEnhancedDeserializationProxy implements MethodInterceptor { private EnhancedDeserializationProxyImpl( Class<?> type, Map<String, ResultLoaderMap.LoadPair> unloadedProperties, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) { super(type, unloadedProperties, objectFactory, constructorArgTypes, constructorArgs); } public static Object createProxy( Object target, Map<String, ResultLoaderMap.LoadPair> unloadedProperties, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) { final Class<?> type = target.getClass(); EnhancedDeserializationProxyImpl callback = new EnhancedDeserializationProxyImpl( type, unloadedProperties, objectFactory, constructorArgTypes, constructorArgs); Object enhanced = crateProxy(type, callback, constructorArgTypes, constructorArgs); PropertyCopier.copyBeanProperties(type, target, enhanced); return enhanced; } @Override public Object intercept(Object enhanced, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { final Object o = super.invoke(enhanced, method, args); return (o instanceof AbstractSerialStateHolder) ? o : methodProxy.invokeSuper(o, args); } @Override protected AbstractSerialStateHolder newSerialStateHolder( Object userBean, Map<String, ResultLoaderMap.LoadPair> unloadedProperties, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) { return new CglibSerialStateHolder( userBean, unloadedProperties, objectFactory, constructorArgTypes, constructorArgs); } } }