使用Redis和Java進行數據庫緩存 - DZone數據庫

數據庫緩存是處理這些性能問題的最多見策略之一。緩存涉及將數據庫查詢的結果保存在更快,更容易訪問的位置。正確完成後,緩存將減小查詢響應時間,減小數據庫負載並下降成本。redis

可是,緩存也須要當心處理,由於它們其實是在另外一個位置建立另外一個信息副本。保持數據庫和緩存同步並保持最新可能比您預期的更棘手。在下一節中,咱們將討論一些最多見的數據庫緩存策略。數據庫

什麼是不一樣的緩存策略?

手動緩存(也稱爲緩存擱置策略)涉及直接管理數據庫和緩存。您的應用程序在啓動數據庫查詢以前檢查緩存,並在對數據庫進行任何更改後更新緩存。編程

雖然若是正確實現有效,但手動緩存可能很是繁瑣,尤爲是在您須要查詢多個數據庫時。出於這些緣由,開發人員發明了許多替代性的緩存策略。緩存

直讀緩存策略

在讀取緩存中,應用程序首先查詢緩存以查看其所需的信息是否在內部。若是沒有,它將從數據庫中檢索信息並使用它來更新緩存。緩存提供程序或緩存庫負責查詢和更新緩存的詳細邏輯。bash

當應用程序重複請求相同的數據時,讀取策略最適合讀取繁重的工做負載:例如,一遍又一遍地加載相同文章的新聞網站。異步

讀取策略的一個缺點是對緩存的第一次查詢將始終致使未命中,由於保證所請求的信息不在內部。爲了解決這個問題,開發人員一般會使用用戶可能要求的信息提早「加熱」緩存。編程語言

直寫緩存策略

在直寫式高速緩存中,首先對高速緩存進行更新,而後對數據庫進行更新。從應用程序到緩存以及從緩存到數據庫都有一條直接線。與直讀式緩存結合使用時,直寫式策略可確保您的數據保持一致,從而無需手動緩存失效。ide

後寫緩存策略

在後寫式緩存(也稱爲回寫式高速緩存)中,應用程序首先將數據寫入高速緩存。通過一段設定的延遲後,緩存也會將此信息寫入數據庫。後寫緩存最適合寫入繁重的工做負載,即便出現一些故障和停機也能夠很好地執行。性能

基於Java的Redis緩存與Redisson

Redis是NoSQL數據庫最受歡迎的選項之一,它使用鍵值系統來存儲數據。Redisson是Java編程語言中的Redis客戶端庫,可使用全部熟悉的Java集合輕鬆訪問Redis功能。網站

Redisson容許您將數據放在外部存儲中的地圖中。您可使用此功能實現數據庫,Web服務或任何其餘數據源的緩存。

Redis中的直讀緩存

下面是一個Java示例,說明如何在Redis和Redisson中使用直讀緩存。 若是請求的條目在緩存中不存在,則它將由MapLoader對象加載:

MapLoader<String, String> mapLoader = new MapLoader<String, String>()
{
	@Override
	public Iterable<String> loadAllKeys()
	{
		List<String>	list		= new ArrayList<String>();
		Statement	statement	= conn.createStatement();
		try {
			ResultSet result = statement.executeQuery( "SELECT id FROM student" );
			while ( result.next() )
			{
				list.add( result.getString( 1 ) );
			}
		} finally {
			statement.close();
		}
		return(list);
	}
 
 
	@Override
	public String load( String key )
	{
		PreparedStatement preparedStatement = conn.prepareStatement( "SELECT name FROM student where id = ?" );
		try {
			preparedStatement.setString( 1, key );
			ResultSet result = preparedStatement.executeQuery();
			if ( result.next() )
			{
				return(result.getString( 1 ) );
			}
			return(null);
		} finally {
			preparedStatement.close();
		}
	}
}
複製代碼

配置使用案例:

MapOptions<K, V> options = MapOptions.< K, V > defaults()
.loader( mapLoader );
RMap<K, V> map = redisson.getMap( "test", options );
/* or */
RMapCache<K, V> map = redisson.getMapCache( "test", options );
/* or with boost up to 45x times */
RLocalCachedMap<K, V> map = redisson.getLocalCachedMap( "test", options );
/* or with boost up to 45x times */
RLocalCachedMapCache<K, V> map = redisson.getLocalCachedMapCache( "test", options );
複製代碼

Redis中的直寫緩存

下面是一個Java示例,說明如何在Redis中使用Redis中的Redis使用直寫緩存。

在MapWriter對象更新緩存和數據庫以前,緩存更新方法不會返回:

MapWriter<String, String> mapWriter = new MapWriter<String, String>()
{
	@Override
	public void writeAll( Map<String, String> map )
	{
		PreparedStatement preparedStatement = conn.prepareStatement( "INSERT INTO student (id, name) values (?, ?)" );
		try {
			for ( Entry<String, String> entry : map.entrySet() )
			{
				preparedStatement.setString( 1, entry.getKey() );
				preparedStatement.setString( 2, entry.getValue() );
				preparedStatement.addBatch();
			}
			preparedStatement.executeBatch();
		} finally {
			preparedStatement.close();
		}
	}
 
 
	@Override
	public void write( String key, String value )
	{
		PreparedStatement preparedStatement = conn.prepareStatement( "INSERT INTO student (id, name) values (?, ?)" );
		try {
			preparedStatement.setString( 1, key );
			preparedStatement.setString( 2, value );
			preparedStatement.executeUpdate();
		} finally {
			preparedStatement.close();
		}
	}
 
 
	@Override
	public void deleteAll( Collection<String> keys )
	{
		PreparedStatement preparedStatement = conn.prepareStatement( "DELETE FROM student where id = ?" );
		try {
			for ( String key : keys )
			{
				preparedStatement.setString( 1, key );
				preparedStatement.addBatch();
			}
			preparedStatement.executeBatch();
		} finally {
			preparedStatement.close();
		}
	}
 
 
	@Override
	public void delete( String key )
	{
		PreparedStatement preparedStatement = conn.prepareStatement( "DELETE FROM student where id = ?" );
		try {
			preparedStatement.setString( 1, key );
			preparedStatement.executeUpdate();
		} finally {
			preparedStatement.close();
		}
	}
}
複製代碼

使用配置案例:

MapOptions<K, V> options = MapOptions.< K, V > defaults()
.writer( mapWriter )
.writeMode( WriteMode.WRITE_THROUGH );
RMap<K, V> map = redisson.getMap( "test", options );
/* or */
RMapCache<K, V> map = redisson.getMapCache( "test", options );
/* or with boost up to 45x times */
RLocalCachedMap<K, V> map = redisson.getLocalCachedMap( "test", options );
/* or with boost up to 45x times */
RLocalCachedMapCache<K, V> map = redisson.getLocalCachedMapCache( "test", options );
複製代碼

Redis中的後寫緩存

MapWriter接口還用於異步提交對Map對象(緩存)和外部存儲(數據庫)的更新。後臺寫入操做執行中使用的線程數量經過writeBehindThreads設置設置。

下面,咱們看到Redisson中基於Redis的後寫緩存實現的配置的Java示例:

MapOptions<K, V> options = MapOptions.< K, V > defaults()
.writer( mapWriter )
.writeMode( WriteMode.WRITE_BEHIND )
.writeBehindThreads( 8 );
RMap<K, V> map = redisson.getMap( "test", options );
/* or */
RMapCache<K, V> map = redisson.getMapCache( "test", options );
/* or with boost up to 45x times */
RLocalCachedMap<K, V> map = redisson.getLocalCachedMap( "test", options );
/* or with boost up to 45x times */
RLocalCachedMapCache<K, V> map = redisson.getLocalCachedMapCache( "test", options );
複製代碼

上述全部討論的策略可用於Redisson的RMap,RMapCache,RLocalCachedMap和RLocalCachedMapCache對象。使用後兩個對象可使Redis中的讀取操做速度提升45倍。

相關文章
相關標籤/搜索