1. 程式人生 > >Spring環境下Mybatis的配置以及工作機制

Spring環境下Mybatis的配置以及工作機制

MyBatis 是一款一流的支援自定義SQL、儲存過程和高階對映的持久化框架。MyBatis 能夠使用簡單的XML 格式或者註解進行來配置,能夠對映基本資料元素、Map 介面和POJO(普通java 物件)到資料庫中的記錄。所有的MyBatis 應用都以SqlSessionFactory 例項為中心。SqlSessionFactory 例項通過SqlSessionFactoryBuilder 來獲得,SqlSessionFactoryBuilder 能夠從XML 配置檔案或者通過自定義編寫的配置類(Configuration class),來建立一個SqlSessionFactory 例項。在非Spring環境下XML檔案的配置如下

<configuration>
  <environments default="development">
     <environment id="development">
     <transactionManager type="JDBC"/>
     <dataSource type="POOLED">
 <span style="white-space:pre">	</span>  <property name="driver" value="${driver}"/>
          <property name="url" value="${url}"/>
          <property name="username" value="${username}"/>
<span style="white-space:pre">	</span>  <property name="password" value="${password}"/>
     </dataSource>
     </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>
上面為Mybatis配置了事務管理器以及資料來源(資料庫連線池)。一般在Spring環境下資料來源以及事務管理器不需要在<configuration />檔案中配置,而是藉助於mybatis-spring包下的org.mybatis.spring.SqlSessionFactoryBean來注入第三方資料來源。mybatis在Spring的 applicationContext.xml 中的配置如下
<!-- 配置mybatis -->
<bean id="mSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
	<property name="dataSource" ref="mDataSource" />
	<property name="configLocation"
		value="classpath:/mysql-mapper/Configuration.xml" />
	<property name="mapperLocations" value="classpath:/mysql-mapper/*Mapper.xml" />
</bean>
	
<!-- 資料來源配置, 使用應用中的DBCP資料庫連線池 -->
<bean id="mDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" >
	<!-- Connection Info -->
	<property name="driverClassName" value="${jdbc.driver}" />
	<property name="url" value="${jdbc.url}" />
	<property name="username" value="${jdbc.username}" />
	<property name="password" value="${jdbc.password}" />

	<!-- Connection Pooling Info -->
	<property name="maxActive" value="${dbcp.maxActive}" />
	<property name="maxIdle" value="${dbcp.maxIdle}" />
	<property name="defaultAutoCommit" value="false" />
	<!-- 連線Idle一個小時後超時 -->
	<property name="timeBetweenEvictionRunsMillis" value="3600000" />
	<property name="minEvictableIdleTimeMillis" value="3600000" />
</bean>
<!-- mybatis Dao -->
<bean id="mBaseDao" class="com.rfidMidware.dao.BaseDao">
	<property name="sqlSessionFactory" ref="mSqlSessionFactory" />
</bean>
由上面的配置可以看出,SqlSessionFactoryBean中注入了第三方dataSource,即dbcp資料來源。同時在配置中給出了mybatis配置檔案以及Mapper對映檔案的路徑。這時我們來看看Spring環境下的mybatis配置檔案是怎麼樣的
<configuration>
	<properties resource="jdbc.properties" />
	<settings>
		<setting name="cacheEnabled" value="true" />
		<setting name="lazyLoadingEnabled" value="false" />
	</settings>
	<typeAliases>
		<typeAlias type="com.rfidMidware.model.controlManager.Manager" alias="Manager" />
	</typeAliases>
</configuration>
觀察上面的配置,可以看出已經不需要再配置資料來源、事務管理器等選項了。順便說說上面的配置吧,<properties />檔案給出了外部屬性檔案。<settings />很重要,用於改變執行中mybatis的行為。可以看出我開了mybatis的二級快取。我們知道Mybatis共分兩級快取(不知道的話可以點開連結喲,個人覺得很好的部落格的連結)。一級快取基於Session,二級快取作用域為Mapper的範圍。但是由於Spring環境下SqlSession是由Spring容器管理的,mybatis的一級快取不再有效。<typeAlias />為類全名產生一個簡短的別名,方便Mapper檔案使用。
配置好了,那麼mybatis具體是如何工作的呢,首先,看一下我們在業務層讀寫資料庫時使用的mybatis的介面吧(這只是使用mybatis的一種方式)
public class BaseDao  extends SqlSessionDaoSupport {

	public int  save(String key, Object object){
		return getSqlSession().insert(key, object);
	}
	
	public int update(String key, Object object){
		return getSqlSession().update(key, object);
	}
	
	public int  update(String key){
		return getSqlSession().update(key);
	}
	
	public int  delete(String key, Serializable id) {
		return getSqlSession().delete(key, id);
	}.................
這裡使用的是繼承SqlSessionDaoSupport的方法。來看看這個類
public abstract class SqlSessionDaoSupport extends DaoSupport {

	  private SqlSession sqlSession;

	  private boolean externalSqlSession;

	  public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
	    if (!this.externalSqlSession) {
	      this.sqlSession = new SqlSessionTemplate(sqlSessionFactory); 	    }
	  }

	  public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
	    this.sqlSession = sqlSessionTemplate;
	    this.externalSqlSession = true;
	  }

	  /**
	   * Users should use this method to get a SqlSession to call its statement methods
	   * This is SqlSession is managed by spring. Users should not commit/rollback/close it
	   * because it will be automatically done.
	   *
	   * @return Spring managed thread safe SqlSession
	   */
	  public SqlSession getSqlSession() {
	    return this.sqlSession;
	  }
	}
當我們使用BaseDao介面,呼叫getSqlSession時會呼叫其基類SqlSessionDaoSupport相應的方法。而這個SqlSession是其子類SqlSessionTemplate 的一個例項。

this.sqlSession = new SqlSessionTemplate(sqlSessionFactory); 

而在上面的配置檔案中有這一句 <property name="sqlSessionFactory" ref="mSqlSessionFactory" />   ,由此處可以看出上句SqlSessionTemplate例項化傳入的引數sqlSessionFactory即 org.mybatis.spring.SqlSessionFactoryBean。 

先來看看SqlSessionTemplate的真面目

public class SqlSessionTemplate implements SqlSession {

	  private final SqlSessionFactory sqlSessionFactory;

	  private final ExecutorType executorType;

	  private final SqlSession sqlSessionProxy;

	  private final PersistenceExceptionTranslator exceptionTranslator;

	  public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
		 PersistenceExceptionTranslator exceptionTranslator) {

			notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
			notNull(executorType, "Property 'executorType' is required");

			 this.sqlSessionFactory = sqlSessionFactory;
			 this.executorType = executorType;
			 this.exceptionTranslator = exceptionTranslator;
			 this.sqlSessionProxy = (SqlSession) newProxyInstance(
			  SqlSessionFactory.class.getClassLoader(), new Class[] { SqlSession.class },new SqlSessionInterceptor());			
		} .......
最重要的是最後一句,使用java的動態代理生成的SqlSessionProxy來執行具體的 資料庫CRUD,JDK的動態代理是基於介面的。該代理實現SqlSession的介面,並使用SqlSessionIntercepter攔截器將mybatis方法引導到正確的由Spring事務管理器產生的SqlSession中去。我們知道動態代理中,當代理類呼叫相應的類方法時候會呼叫InvocationHandler中的invoke方法。而SqlSessionIntercepter是InvocationHandler的子類,這個攔截器中最重要的的是invoke方法

private class SqlSessionInterceptor implements InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      SqlSession sqlSession = getSqlSession(
          SqlSessionTemplate.this.sqlSessionFactory,
          SqlSessionTemplate.this.executorType,
          SqlSessionTemplate.this.exceptionTranslator);
      }

攔截器中getSession方法呼叫org.mybatis.spring.SqlSessionUtils中的 靜態 getSession方法;我們再觀察這個方法(已精簡)

public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {

    //需同步時用holder來管理sqlSession
    SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);

    if (holder != null && holder.isSynchronizedWithTransaction()) {
      if (holder.getExecutorType() != executorType) {
        throw new TransientDataAccessResourceException("Cannot change the ExecutorType when there is an existing transaction");
      }
      holder.requested();

      return holder.getSqlSession();
    }
   SqlSession session = sessionFactory.openSession(executorType);
    ................
    return session;
  }
注意到這一句SqlSession session = sessionFactory.openSession(executorType);呼叫傳遞過來的sessionFactory來開啟一個sqlSession。上文說到Spring注入的sqlSessionFactory是org.mybatis.spring.SqlSessionFactoryBean。  SqlSessionFactoryBean這個類是用來生成SqlSessionFactory的,這也是一般情況下在Spring環境下生成一個共享的SqlSessionFactory的方法。實際上依賴注入時向基於mybatis的DAO介面(此例中即為BaseDao)注入的是其內部生成的SqlSessionFactory
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {

			  private static final Log logger = LogFactory.getLog(SqlSessionFactoryBean.class);

			  private Resource configLocation;

			  private Resource[] mapperLocations;

			  private DataSource dataSource;

			  private TransactionFactory transactionFactory;

			  private Properties configurationProperties;

			  private SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

			  private SqlSessionFactory sqlSessionFactory;

			  private String environment = SqlSessionFactoryBean.class.getSimpleName(); // EnvironmentAware requires spring 3.1

; .............}
可以看出SqlSessionFactoryBean中包含了dataSource、sqlSessionFactoryBuilder、sqlSessionFactory以及配置檔案Configuration等等的例項,該類使用

this.sqlSessionFactory = buildSqlSessionFactory(); 

而buildSqlSessionFactory又呼叫this.sqlSessionFactoryBuilder.build(configuration);

再來看看這個build方法

public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }
聯絡上文可知為BaseDao注入的SqlSessionFactory即為此處的 DefaultSqlSessionFactroy,同時傳入配置檔案Configuration的例項作為引數。所以上文呼叫openSession有兩種方法 openSessionFromDataSource 和 openSessionFromConnection
public class DefaultSqlSessionFactory implements SqlSessionFactory {

  private final Configuration configuration;

  public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
      Transaction tx = null;
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      final Executor executor = configuration.newExecutor(tx, execType);  //<strong><span style="color:#ff0000;">這是實際執行SQL語句的執行器</span></strong>
      return new DefaultSqlSession(configuration, executor, autoCommit);  //<span style="color:#ff0000;"><strong>可知 這就是我們所用的SqlSession的本來面目</strong></span>
   
  }
public SqlSession openSession(Connection connection) {
    return openSessionFromConnection(configuration.getDefaultExecutorType(), connection);
  }
由上可知,我們實際上使用的SqlSession即為其子類 DefaultSqlSession.
public class DefaultSqlSession implements SqlSession {

  private Configuration configuration;
  private Executor executor;

  private boolean autoCommit;
  private boolean dirty;
  
  public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
    this.configuration = configuration;
    this.executor = executor;
    this.dirty = false;
    this.autoCommit = autoCommit;
  }...............................
DefaultSqlSession實現了SqlSession的所有介面,仔細檢視原始碼可以明顯看出 實際上負責執行SQL語句的是Executor。

Executor的生成,則是通過 org.apache.ibatis.session.Configuration的 newExecutor方法生成。

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
	    executorType = executorType == null ? defaultExecutorType : executorType;
	    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
	    Executor executor;
	    if (ExecutorType.BATCH == executorType) {
	      executor = new BatchExecutor(this, transaction);
	    } else if (ExecutorType.REUSE == executorType) {
	      executor = new ReuseExecutor(this, transaction);
	    } else {
	      executor = new SimpleExecutor(this, transaction);
	    }
	    if (cacheEnabled) {
	      executor = new CachingExecutor(executor);
	    }
	    executor = (Executor) interceptorChain.pluginAll(executor);
	    return executor;
	  }
可以看出,如果不開啟cache的話,建立的Executor只是3中基礎型別之一,BatchExecutor專門用於執行批量sql操作,ReuseExecutor會重用statement執行sql操作,SimpleExecutor只是簡單執行sql沒有什麼特別的。開啟cache的話(預設是開啟的並且沒有任何理由去關閉它),就會建立CachingExecutor,它以前面建立的Executor作為唯一引數。CachingExecutor在查詢資料庫前先查詢快取,若沒找到的話呼叫delegate(就是構造時傳入的Executor物件)從資料庫查詢,並將查詢結果存入快取中。Executor物件是可以被外掛攔截的,如果定義了針對Executor型別的外掛,最終生成的Executor物件是被各個外掛插入後的代理物件。(mybatis的分頁是基於記憶體的邏輯分頁,資料量比較大時候往往會佔用過多記憶體,一般提倡的分頁方式是物理分頁,這就需要自己通過攔截器來實現)。
public class SimpleExecutor extends BaseExecutor {

		  public SimpleExecutor(Configuration configuration, Transaction transaction) {
		    super(configuration, transaction);
		  }

		  public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
		    Statement stmt = null;
		    try {
		      Configuration configuration = ms.getConfiguration();
		      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
		      stmt = prepareStatement(handler, ms.getStatementLog());
		      return handler.update(stmt);
		    } finally {
		      closeStatement(stmt);
		    }
		  }
可以看出,Executor的具體工作都交由 StatementHandler來執行。而StatementHandler也是在Configuration中生成的。
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, 
						RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

	 StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);

	 statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);

	 return statementHandler;
 }
可以看到每次建立的StatementHandler都是RoutingStatementHandler,它只是一個分發者,他一個屬性delegate用於指定用哪種具體的StatementHandler。可選的StatementHandler有 SimpleStatementHandlerPreparedStatementHandlerCallableStatementHandler三種。選用哪種在mapper配置檔案的每個statement裡指定,預設的是PreparedStatementHandler。同時還要注意到StatementHandler是可以被攔截器攔截的,和Executor一樣,被攔截器攔截後的對像是一個代理物件。由於mybatis沒有實現資料庫的物理分頁,眾多物理分頁的實現都是在這個地方使用攔截器實現的。
 public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

		    switch (ms.getStatementType()) {
		      case STATEMENT:
			delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
			break;
		      case PREPARED:
			delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
			break;
		      case CALLABLE:
			delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
			break;
		      default:
			throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
		    }

		  }
StatementHandler建立後需要執行一些初始操作,比如statement的開啟和引數設定、對於PreparedStatement還需要執行引數的設定操作等。在具體的 Executor中執行。程式碼如下:
 private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
	    Statement stmt;
	    Connection connection = getConnection(statementLog);
	    stmt = handler.prepare(connection);
	    handler.parameterize(stmt);
	    return stmt;
	  }
其中handler的引數化方法 此handler即PreparedStatementHandler 
public void parameterize(Statement statement) throws SQLException {
	    parameterHandler.setParameters((PreparedStatement) statement);
	  }
其中 parameterHandler 在 PreparedStatementHandler的基類中BaseStatementHandler
public abstract class BaseStatementHandler implements StatementHandler {

		  protected final Configuration configuration;
		  protected final ObjectFactory objectFactory;
		  protected final TypeHandlerRegistry typeHandlerRegistry;
		  protected final ResultSetHandler resultSetHandler;
		  protected final ParameterHandler parameterHandler;

		  protected final Executor executor;
		  protected final MappedStatement mappedStatement;
		  protected final RowBounds rowBounds;

		  protected BoundSql boundSql;
其中 this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql); 在Configuration中生成
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
		    ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
		    parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
		    return parameterHandler;
		  }
其中 mappedStatement.getLang()返回languageDriver
public class XMLLanguageDriver implements LanguageDriver {
 public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
   return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
 }
即生成DefaultParameterHandler
public class DefaultParameterHandler implements ParameterHandler {

		  private final TypeHandlerRegistry typeHandlerRegistry;

		  private final MappedStatement mappedStatement;
		  private final Object parameterObject;
		  private BoundSql boundSql;
		  private Configuration configuration;

		  public DefaultParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
		    this.mappedStatement = mappedStatement;
		    this.configuration = mappedStatement.getConfiguration();
		    this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
		    this.parameterObject = parameterObject;
		    this.boundSql = boundSql;
		  }

		  public Object getParameterObject() {
		    return parameterObject;
		  }

		  public void setParameters(PreparedStatement ps) throws SQLException {
		    ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
		    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
		    if (parameterMappings != null) {
		      for (int i = 0; i < parameterMappings.size(); i++) {
			ParameterMapping parameterMapping = parameterMappings.get(i);
			if (parameterMapping.getMode() != ParameterMode.OUT) {
			  Object value;
			  String propertyName = parameterMapping.getProperty();
			  if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
			    value = boundSql.getAdditionalParameter(propertyName);
			  } else if (parameterObject == null) {
			    value = null;
			  } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
			    value = parameterObject;
			  } else {
			    MetaObject metaObject = configuration.newMetaObject(parameterObject);
			    value = metaObject.getValue(propertyName);
			  }
			  TypeHandler typeHandler = parameterMapping.getTypeHandler();
			  JdbcType jdbcType = parameterMapping.getJdbcType();
			  if (value == null && jdbcType == null) jdbcType = configuration.getJdbcTypeForNull();
			  typeHandler.setParameter(ps, i + 1, value, jdbcType);
			}
		      }
		    }
		  }

		}
這裡面最重要的一句其實就是最後一句程式碼,它的作用是用合適的TypeHandler完成引數的設定。那麼什麼是合適的TypeHandler呢,它又是如何決斷出來的呢?BaseStatementHandler的構造方法有這麼一句:
this.boundSql= mappedStatement.getBoundSql(parameterObject);
它觸發了sql 的解析,在解析sql的過程中,TypeHandler也被決斷出來了,決斷的原則就是根據引數的型別和引數對應的JDBC型別決定使用哪個TypeHandler。比如:引數型別是String的話就用StringTypeHandler,引數型別是整數的話就用IntegerTypeHandler等。
引數設定完畢後,執行資料庫操作(update或query)。如果是query最後還有個查詢結果的處理過程。

如果再結合Mybatis幾個重要類來分析一下具體Sql語句的生成過程,瞭解一下MappedStatement、SqlSource等類 相信Mybatis的實現機制應該就比較清楚了。先寫到這裡了,如果有疏漏錯誤處,多多指出啊。










相關推薦

Spring環境Mybatis配置以及工作機制

MyBatis 是一款一流的支援自定義SQL、儲存過程和高階對映的持久化框架。MyBatis 能夠使用簡單的XML 格式或者註解進行來配置,能夠對映基本資料元素、Map 介面和POJO(普通java 物件)到資料庫中的記錄。所有的MyBatis 應用都以SqlSession

Spring環境MyBatis支援多個Datasource參考實現

需求背景 最近接到一個專案,需要改造一個老的系統。該老系統以Oracle為儲存,巨量的PL/SQL程式碼實現業務程式碼,C實現Socket Server,作為Client和PL/SQL的橋樑。不出所料,該老系統最大的問題是PL/SQL程式碼量巨大(上萬的Procedure好幾個),且毫無

spring bootmybatis配置雙資料來源

最近專案上遇到需要雙資料來源的來實現需求,並且需要基於spring boot,mybatis的方式來實現,在此做簡單記錄。 單一資料來源配置 單一資料來源配置的話並沒有什麼特別的,在spring boot框架下,只需要在配置檔案內新增對應的配置項即可,sprin

MybatisSpring環境的啟動順序

app new XML otc blank mybatis ssp builds highlight 主要看三個類: mybatis-spring-1.2.2.jar包 -> org.mybatis.spring.SqlSessionFactoryBean mybat

Spring環境Mybatis+Druid對資料庫密碼加密

匯入jar包(mybatis+druid+mysql) 使用druid生成加密後的密碼 在jar包所在路徑下,開啟cmd視窗,執行:java -cp druid-1.1.10.jar com.alibaba.druid.filter.config.ConfigTools yourpassword

NDK環境變數的配置以及編譯方法(linux環境

1、下載NDK 2 、配置NDK的環境變數 a 、sudo gedit .bashrc (這裡的bashrc檔案在不同電腦下所在的路徑不同) b 、export PATH=$PATH:/work/

Spring在mac配置以及簡單使用

在網上搜索Spring的安裝與配置,大多數都是在Windows平臺下,且在eclipse下的配置。 這次我來把自己在mac系統下以及在IDEA開發環境下的配置寫成部落格,希望能給予幫助。 其實,配置Spring不管在哪個環境下都是大同小異,下載Spring-

Spring Boot 便捷修改生產環境和測試環境配置檔案

期初在網路上百度,搜出五花八門的內容,最後覺得都很複雜和麻煩,索性就大膽猜測了一下,結果行的通,方式如下: 準備三個Spring Boot工程的配置檔案,名字命名分別如下圖:  在主配置檔案中只需要這樣寫即可: spring.profiles.active=test

spring中通過Profile配置不同環境log配置

一般我們在開發的時候,希望log打到控制檯上,而在釋出的時候,希望打到檔案裡面。在spring裡面可以通過profile進行切換。 在application.yml裡面,每個profile增加 logging: config: classpath:log-dev.xm

windows環境caffe編譯以及python介面配置教程(超詳細)

前言: 這週一直在搞caffe。編譯開原始碼是一件很痛苦的事情,在教程開始之前,還是建議同學要有耐心,不要怕麻煩,一步一步來,等到調通之日,發現確實沒有想象之中那麼複雜。 一、材料準備 1、下載ca

mybatis+spring環境快取的使用和mybatis一級快取失效原因

這些天由於專案存在資料訪問的效能問題,研究了下快取在各個階段的應用,一般來說,可以在5個方面進行快取的設計: 1.最底層可以配置的是MySQL自帶的query cache, 2.mybatis的一級快取,預設情況下都處於開啟狀態,只能使用自帶的PerpetualCac

macadb環境變數的配置以及command not found的解決

關於這類文章,網上已經有不少的配置方法。我試過了所有的方法都不可行。納悶了一天才解決了。 首先,配置步驟:開啟終端,依次輸入, cd ~ touch  .bash_profile open -e .bash_profile  這時就能開啟.bash_profile這個配置使

MyBatisSpring環境的事務管理

MyBatis的設計思想很簡單,可以看做是對JDBC的一次封裝,並提供強大的動態SQL對映功能。但是由於它本身也有一些快取、事務管理等功能,所以實際使用中還是會碰到一些問題——另外,最近接觸了JFinal,其思想和Hibernate類似,但要更簡潔,和MyBatis的設計思想不同,但有一點相同:都是想通過簡潔

Windows環境安裝配置Anaconda的Python開發環境

anacondaPython官方自帶的軟件只有基礎的庫文件,而在編程過程中需要使用各種類型的庫,都需要花費大量的時間去查找並不斷下載庫文件並加載到環境中去才能使用,這也是我自學Python遇到的一個困難點,anaconda提供了一個整合的環境解決了這個問題。 官方下載地址如下:(這裏選擇的是windows版本

目標檢測算法SSD在window環境GPU配置訓練自己的數據集

等等 過程 采集 span 數據轉換 都是 too bsp nvidia 由於最近想試一下牛掰的目標檢測算法SSD。於是乎,自己做了幾千張數據(實際只有幾百張,利用數據擴充算法比如鏡像,噪聲,切割,旋轉等擴充到了幾千張,其實還是很不夠)。於是在網上找了相關的介紹,自己處理數

Linux環境Swap配置方法

cache post /etc/ setting 情況 buffers 是否 mks sta Linux環境下Swap配置方法 場景: 今天下午安裝一個CentOS6.5操作系統,忘記配置swap分區。看看如何安裝系統之後,增加和刪除swap分區。方法如下:1.內存占

windows環境wampserver配置https

bin 註釋 每天 圖片 自己 發生 example 正常 pac 因為公司業務主要是在微信上進行開展的,所以作為程序員的我們每天的開發任務就都是在與微信打交道,這個時候我們就需要在本地配置端口映射到外網,方便我們在微信客戶端進行調試。 最近某種需要,所以需要配置 http

Linux環境安裝配置Node.js

目錄 .com inf inux .tar.gz bsp ln -s mir registry 1、在官網查看版本,LTS代表長期支持的版本 2、進入服務器 3、輸入命令:·wget https://npm.taobao.org/mirrors/nod

win10 +python3.6環境安裝opencv以及pycharm導入cv2有問題的解決辦法

eclipse 需要 info nbsp tail 博客 令行 嘗試 功能 一、安裝opencv   借鑒的這篇博客已經寫得很清楚了--------https://blog.csdn.net/u011321546/article/details/79499598

eclipse環境如何配置tomcat

分享圖片 runtime sdn https env title 自己 cli 配置tomcat 打開Eclipse,單擊“Window”菜單,選擇下方的“Preferences”。 單擊“Server”選項,選擇下方的“Runtime Environments”。