Feature - Hibernate 6 support #4322
parent
bf3849f6ca
commit
1e38128276
@ -0,0 +1,98 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson-hibernate</artifactId>
|
||||
<version>3.17.3-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>redisson-hibernate-6</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Redisson/Hibernate-6.x+</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.orm</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
<version>6.0.2.Final</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate.orm</groupId>
|
||||
<artifactId>hibernate-testing</artifactId>
|
||||
<version>6.0.2.Final</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>5.7.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-params</artifactId>
|
||||
<version>5.7.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.1.2</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<Build-Time>${maven.build.timestamp}</Build-Time>
|
||||
<Automatic-Module-Name>redisson.hibernate53</Automatic-Module-Name>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>com.mycila</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<version>3.0</version>
|
||||
<configuration>
|
||||
<basedir>${basedir}</basedir>
|
||||
<header>${basedir}/../../header.txt</header>
|
||||
<quiet>false</quiet>
|
||||
<failIfMissing>true</failIfMissing>
|
||||
<aggregate>false</aggregate>
|
||||
<includes>
|
||||
<include>src/main/java/org/redisson/</include>
|
||||
</includes>
|
||||
<excludes>
|
||||
<exclude>target/**</exclude>
|
||||
</excludes>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<mapping>
|
||||
<java>JAVADOC_STYLE</java>
|
||||
</mapping>
|
||||
<strictCheck>true</strictCheck>
|
||||
<useDefaultMapping>true</useDefaultMapping>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2013-2021 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.engine.jndi.JndiException;
|
||||
import org.hibernate.engine.jndi.spi.JndiService;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.redisson.api.RedissonClient;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Hibernate Cache region factory based on Redisson.
|
||||
* Uses Redisson instance located in JNDI.
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class JndiRedissonRegionFactory extends RedissonRegionFactory {
|
||||
|
||||
private static final long serialVersionUID = -4814502675083325567L;
|
||||
|
||||
public static final String JNDI_NAME = CONFIG_PREFIX + "jndi_name";
|
||||
|
||||
@Override
|
||||
protected RedissonClient createRedissonClient(StandardServiceRegistry registry, Map properties) {
|
||||
String jndiName = ConfigurationHelper.getString(JNDI_NAME, properties);
|
||||
if (jndiName == null) {
|
||||
throw new CacheException(JNDI_NAME + " property not set");
|
||||
}
|
||||
|
||||
try {
|
||||
return (RedissonClient) registry.getService(JndiService.class).locate(jndiName);
|
||||
} catch (JndiException e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void releaseFromUse() {
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright (c) 2013-2021 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.hibernate.PropertyNotFoundException;
|
||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.redisson.client.codec.Codec;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonCacheKeysFactory extends DefaultCacheKeysFactory {
|
||||
|
||||
private final Codec codec;
|
||||
|
||||
public RedissonCacheKeysFactory(Codec codec) {
|
||||
this.codec = codec;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object createCollectionKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
|
||||
try {
|
||||
String[] parts = persister.getRole().split("\\.");
|
||||
Field f = ReflectHelper.findField(id.getClass(), parts[parts.length - 1]);
|
||||
|
||||
Object prev = f.get(id);
|
||||
f.set(id, null);
|
||||
ByteBuf state = codec.getMapKeyEncoder().encode(id);
|
||||
Object newId = codec.getMapKeyDecoder().decode(state, null);
|
||||
state.release();
|
||||
f.set(id, prev);
|
||||
return super.createCollectionKey(newId, persister, factory, tenantIdentifier);
|
||||
} catch (PropertyNotFoundException e) {
|
||||
return super.createCollectionKey(id, persister, factory, tenantIdentifier);
|
||||
} catch (IllegalAccessException | IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,241 @@
|
||||
/**
|
||||
* Copyright (c) 2013-2021 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.boot.registry.selector.spi.StrategySelector;
|
||||
import org.hibernate.boot.spi.SessionFactoryOptions;
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.cfg.spi.DomainDataRegionBuildingContext;
|
||||
import org.hibernate.cache.cfg.spi.DomainDataRegionConfig;
|
||||
import org.hibernate.cache.spi.CacheKeysFactory;
|
||||
import org.hibernate.cache.spi.DomainDataRegion;
|
||||
import org.hibernate.cache.spi.access.AccessType;
|
||||
import org.hibernate.cache.spi.support.*;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.redisson.Redisson;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.api.RScript;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.redisson.client.codec.LongCodec;
|
||||
import org.redisson.config.Config;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Hibernate Cache region factory based on Redisson.
|
||||
* Creates own Redisson instance during region start.
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonRegionFactory extends RegionFactoryTemplate {
|
||||
|
||||
private static final long serialVersionUID = 3785315696581773811L;
|
||||
|
||||
public static final String QUERY_DEF = "query";
|
||||
|
||||
public static final String COLLECTION_DEF = "collection";
|
||||
|
||||
public static final String ENTITY_DEF = "entity";
|
||||
|
||||
public static final String NATURAL_ID_DEF = "naturalid";
|
||||
|
||||
public static final String TIMESTAMPS_DEF = "timestamps";
|
||||
|
||||
public static final String MAX_ENTRIES_SUFFIX = ".eviction.max_entries";
|
||||
|
||||
public static final String TTL_SUFFIX = ".expiration.time_to_live";
|
||||
|
||||
public static final String MAX_IDLE_SUFFIX = ".expiration.max_idle_time";
|
||||
|
||||
public static final String CONFIG_PREFIX = "hibernate.cache.redisson.";
|
||||
|
||||
public static final String REDISSON_CONFIG_PATH = CONFIG_PREFIX + "config";
|
||||
|
||||
public static final String FALLBACK = CONFIG_PREFIX + "fallback";
|
||||
|
||||
private RedissonClient redisson;
|
||||
private CacheKeysFactory cacheKeysFactory;
|
||||
protected boolean fallback;
|
||||
|
||||
@Override
|
||||
protected CacheKeysFactory getImplicitCacheKeysFactory() {
|
||||
return cacheKeysFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepareForUse(SessionFactoryOptions settings, @SuppressWarnings("rawtypes") Map properties) throws CacheException {
|
||||
this.redisson = createRedissonClient(settings.getServiceRegistry(), properties);
|
||||
|
||||
String fallbackValue = (String) properties.getOrDefault(FALLBACK, "false");
|
||||
fallback = Boolean.valueOf(fallbackValue);
|
||||
|
||||
StrategySelector selector = settings.getServiceRegistry().getService(StrategySelector.class);
|
||||
cacheKeysFactory = selector.resolveDefaultableStrategy(CacheKeysFactory.class,
|
||||
properties.get(Environment.CACHE_KEYS_FACTORY), new RedissonCacheKeysFactory(redisson.getConfig().getCodec()));
|
||||
}
|
||||
|
||||
protected RedissonClient createRedissonClient(StandardServiceRegistry registry, Map properties) {
|
||||
Config config = null;
|
||||
if (!properties.containsKey(REDISSON_CONFIG_PATH)) {
|
||||
config = loadConfig(RedissonRegionFactory.class.getClassLoader(), "redisson.json");
|
||||
if (config == null) {
|
||||
config = loadConfig(RedissonRegionFactory.class.getClassLoader(), "redisson.yaml");
|
||||
}
|
||||
} else {
|
||||
String configPath = ConfigurationHelper.getString(REDISSON_CONFIG_PATH, properties);
|
||||
config = loadConfig(RedissonRegionFactory.class.getClassLoader(), configPath);
|
||||
if (config == null) {
|
||||
config = loadConfig(configPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (config == null) {
|
||||
throw new CacheException("Unable to locate Redisson configuration");
|
||||
}
|
||||
|
||||
return Redisson.create(config);
|
||||
}
|
||||
|
||||
private Config loadConfig(String configPath) {
|
||||
try {
|
||||
return Config.fromYAML(new File(configPath));
|
||||
} catch (IOException e) {
|
||||
// trying next format
|
||||
try {
|
||||
return Config.fromJSON(new File(configPath));
|
||||
} catch (IOException e1) {
|
||||
throw new CacheException("Can't parse default yaml config", e1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Config loadConfig(ClassLoader classLoader, String fileName) {
|
||||
InputStream is = classLoader.getResourceAsStream(fileName);
|
||||
if (is != null) {
|
||||
try {
|
||||
return Config.fromYAML(is);
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
is = classLoader.getResourceAsStream(fileName);
|
||||
return Config.fromJSON(is);
|
||||
} catch (IOException e1) {
|
||||
throw new CacheException("Can't parse yaml config", e1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void releaseFromUse() {
|
||||
redisson.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMinimalPutsEnabledByDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessType getDefaultAccessType() {
|
||||
return AccessType.TRANSACTIONAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long nextTimestamp() {
|
||||
long time = System.currentTimeMillis() << 12;
|
||||
try {
|
||||
return redisson.getScript(LongCodec.INSTANCE).eval(RScript.Mode.READ_WRITE,
|
||||
"local currentTime = redis.call('get', KEYS[1]);"
|
||||
+ "if currentTime == false then "
|
||||
+ "redis.call('set', KEYS[1], ARGV[1]); "
|
||||
+ "return ARGV[1]; "
|
||||
+ "end;"
|
||||
+ "local nextValue = math.max(tonumber(ARGV[1]), tonumber(currentTime) + 1); "
|
||||
+ "redis.call('set', KEYS[1], nextValue); "
|
||||
+ "return nextValue;",
|
||||
RScript.ReturnType.INTEGER, Arrays.<Object>asList("redisson-hibernate-timestamp"), time);
|
||||
} catch (Exception e) {
|
||||
if (fallback) {
|
||||
return super.nextTimestamp();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainDataRegion buildDomainDataRegion(
|
||||
DomainDataRegionConfig regionConfig,
|
||||
DomainDataRegionBuildingContext buildingContext) {
|
||||
verifyStarted();
|
||||
return new DomainDataRegionImpl(
|
||||
regionConfig,
|
||||
this,
|
||||
createDomainDataStorageAccess( regionConfig, buildingContext ),
|
||||
getImplicitCacheKeysFactory(),
|
||||
buildingContext
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DomainDataStorageAccess createDomainDataStorageAccess(DomainDataRegionConfig regionConfig,
|
||||
DomainDataRegionBuildingContext buildingContext) {
|
||||
String defaultKey = null;
|
||||
if (!regionConfig.getCollectionCaching().isEmpty()) {
|
||||
defaultKey = COLLECTION_DEF;
|
||||
} else if (!regionConfig.getEntityCaching().isEmpty()) {
|
||||
defaultKey = ENTITY_DEF;
|
||||
} else if (!regionConfig.getNaturalIdCaching().isEmpty()) {
|
||||
defaultKey = NATURAL_ID_DEF;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unable to determine entity cache type!");
|
||||
}
|
||||
|
||||
RMapCache<Object, Object> mapCache = getCache(qualifyName(regionConfig.getRegionName()), buildingContext.getSessionFactory().getProperties(), defaultKey);
|
||||
return new RedissonStorage(mapCache, ((Redisson)redisson).getConnectionManager(), buildingContext.getSessionFactory().getProperties(), defaultKey);
|
||||
}
|
||||
|
||||
private String qualifyName(String name) {
|
||||
return RegionNameQualifier.INSTANCE.qualify(name, getOptions());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StorageAccess createQueryResultsRegionStorageAccess(String regionName,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
RMapCache<Object, Object> mapCache = getCache(qualifyName(regionName), sessionFactory.getProperties(), QUERY_DEF);
|
||||
return new RedissonStorage(mapCache, ((Redisson)redisson).getConnectionManager(), sessionFactory.getProperties(), QUERY_DEF);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StorageAccess createTimestampsRegionStorageAccess(String regionName,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
RMapCache<Object, Object> mapCache = getCache(qualifyName(regionName), sessionFactory.getProperties(), TIMESTAMPS_DEF);
|
||||
return new RedissonStorage(mapCache, ((Redisson)redisson).getConnectionManager(), sessionFactory.getProperties(), TIMESTAMPS_DEF);
|
||||
}
|
||||
|
||||
protected RMapCache<Object, Object> getCache(String regionName, Map properties, String defaultKey) {
|
||||
return redisson.getMapCache(regionName);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,196 @@
|
||||
/**
|
||||
* Copyright (c) 2013-2021 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.support.DomainDataStorageAccess;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.redisson.api.RFuture;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.connection.ConnectionManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonStorage implements DomainDataStorageAccess {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(RedissonStorage.class);
|
||||
|
||||
private final RMapCache<Object, Object> mapCache;
|
||||
|
||||
private final ConnectionManager connectionManager;
|
||||
|
||||
int ttl;
|
||||
int maxIdle;
|
||||
int size;
|
||||
boolean fallback;
|
||||
volatile boolean fallbackMode;
|
||||
|
||||
public RedissonStorage(RMapCache<Object, Object> mapCache, ConnectionManager connectionManager, Map<String, Object> properties, String defaultKey) {
|
||||
super();
|
||||
this.mapCache = mapCache;
|
||||
this.connectionManager = connectionManager;
|
||||
|
||||
String maxEntries = getProperty(properties, mapCache.getName(), defaultKey, RedissonRegionFactory.MAX_ENTRIES_SUFFIX);
|
||||
if (maxEntries != null) {
|
||||
size = Integer.valueOf(maxEntries);
|
||||
mapCache.setMaxSize(size);
|
||||
}
|
||||
String timeToLive = getProperty(properties, mapCache.getName(), defaultKey, RedissonRegionFactory.TTL_SUFFIX);
|
||||
if (timeToLive != null) {
|
||||
ttl = Integer.valueOf(timeToLive);
|
||||
}
|
||||
String maxIdleTime = getProperty(properties, mapCache.getName(), defaultKey, RedissonRegionFactory.MAX_IDLE_SUFFIX);
|
||||
if (maxIdleTime != null) {
|
||||
maxIdle = Integer.valueOf(maxIdleTime);
|
||||
}
|
||||
|
||||
String fallbackValue = (String) properties.getOrDefault(RedissonRegionFactory.FALLBACK, "false");
|
||||
fallback = Boolean.valueOf(fallbackValue);
|
||||
}
|
||||
|
||||
private String getProperty(Map<String, Object> properties, String name, String defaultKey, String suffix) {
|
||||
String maxEntries = (String) properties.get(RedissonRegionFactory.CONFIG_PREFIX + name + suffix);
|
||||
if (maxEntries != null) {
|
||||
return maxEntries;
|
||||
}
|
||||
String defValue = (String) properties.get(RedissonRegionFactory.CONFIG_PREFIX + defaultKey + suffix);
|
||||
if (defValue != null) {
|
||||
return defValue;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void ping() {
|
||||
fallbackMode = true;
|
||||
connectionManager.newTimeout(t -> {
|
||||
RFuture<Boolean> future = mapCache.isExistsAsync();
|
||||
future.whenComplete((r, ex) -> {
|
||||
if (ex == null) {
|
||||
fallbackMode = false;
|
||||
} else {
|
||||
ping();
|
||||
}
|
||||
});
|
||||
}, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getFromCache(Object key, SharedSessionContractImplementor session) {
|
||||
if (fallbackMode) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
if (maxIdle == 0 && size == 0) {
|
||||
return mapCache.getWithTTLOnly(key);
|
||||
}
|
||||
|
||||
return mapCache.get(key);
|
||||
} catch (Exception e) {
|
||||
if (fallback) {
|
||||
ping();
|
||||
logger.error(e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putIntoCache(Object key, Object value, SharedSessionContractImplementor session) {
|
||||
if (fallbackMode) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mapCache.fastPut(key, value, ttl, TimeUnit.MILLISECONDS, maxIdle, TimeUnit.MILLISECONDS);
|
||||
} catch (Exception e) {
|
||||
if (fallback) {
|
||||
ping();
|
||||
logger.error(e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object key) {
|
||||
if (fallbackMode) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return mapCache.containsKey(key);
|
||||
} catch (Exception e) {
|
||||
if (fallback) {
|
||||
ping();
|
||||
logger.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evictData() {
|
||||
if (fallbackMode) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mapCache.clear();
|
||||
} catch (Exception e) {
|
||||
if (fallback) {
|
||||
ping();
|
||||
logger.error(e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evictData(Object key) {
|
||||
if (fallbackMode) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mapCache.fastRemove(key);
|
||||
} catch (Exception e) {
|
||||
if (fallback) {
|
||||
ping();
|
||||
logger.error(e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
try {
|
||||
mapCache.destroy();
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2013-2021 Nikita Koksharov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.hibernate.boot.registry.selector.SimpleStrategyRegistrationImpl;
|
||||
import org.hibernate.boot.registry.selector.StrategyRegistration;
|
||||
import org.hibernate.boot.registry.selector.StrategyRegistrationProvider;
|
||||
import org.hibernate.cache.spi.RegionFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class RedissonStrategyRegistrationProvider implements StrategyRegistrationProvider {
|
||||
|
||||
@Override
|
||||
public Iterable<StrategyRegistration> getStrategyRegistrations() {
|
||||
return Collections.<StrategyRegistration>singleton(new SimpleStrategyRegistrationImpl(
|
||||
RegionFactory.class,
|
||||
RedissonRegionFactory.class,
|
||||
"redisson",
|
||||
RedissonRegionFactory.class.getName(),
|
||||
RedissonRegionFactory.class.getSimpleName()));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1 @@
|
||||
org.redisson.hibernate.RedissonStrategyRegistrationProvider
|
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<blueprint default-activation="eager"
|
||||
xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
<bean id="strategyRegistrationProvider" class="org.redisson.hibernate.RedissonStrategyRegistrationProvider"/>
|
||||
|
||||
<service ref="strategyRegistrationProvider" interface="org.hibernate.boot.registry.selector.StrategyRegistrationProvider"/>
|
||||
|
||||
</blueprint>
|
@ -0,0 +1,123 @@
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.stat.Statistics;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class CollectionTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Entity
|
||||
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
|
||||
public static class A implements Serializable {
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
@Column(unique = true) String uniqueField;
|
||||
|
||||
@ManyToMany
|
||||
@JoinTable(
|
||||
name = "a_b",
|
||||
joinColumns = @JoinColumn(
|
||||
name = "unique_field", referencedColumnName = "uniqueField"),
|
||||
inverseJoinColumns = @JoinColumn(
|
||||
name = "b_id", referencedColumnName = "id"))
|
||||
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
|
||||
private List<B> bs = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
|
||||
public static class B implements Serializable {
|
||||
@Id Long id;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { A.class, B.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration cfg) {
|
||||
super.configure(cfg);
|
||||
cfg.setProperty(Environment.DRIVER, org.h2.Driver.class.getName());
|
||||
cfg.setProperty(Environment.URL, "jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;");
|
||||
cfg.setProperty(Environment.USER, "sa");
|
||||
cfg.setProperty(Environment.PASS, "");
|
||||
cfg.setProperty(Environment.CACHE_REGION_PREFIX, "");
|
||||
cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
|
||||
|
||||
cfg.setProperty(Environment.SHOW_SQL, "true");
|
||||
cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "true");
|
||||
cfg.setProperty(Environment.USE_QUERY_CACHE, "true");
|
||||
cfg.setProperty(Environment.CACHE_REGION_FACTORY, RedissonRegionFactory.class.getName());
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
sessionFactory().getCache().evictEntityData();
|
||||
sessionFactory().getStatistics().clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuery() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
A a = new A();
|
||||
a.id = 1L;
|
||||
a.uniqueField = "1";
|
||||
B b = new B();
|
||||
b.id = 1L;
|
||||
s.save(b);
|
||||
a.bs.add(b);
|
||||
s.save(a);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
A a1 = s.get(A.class, 1L);
|
||||
System.out.println("here1");
|
||||
assertThat(a1.bs).hasSize(1);
|
||||
s.getTransaction().commit();
|
||||
|
||||
Assert.assertEquals(0, stats.getDomainDataRegionStatistics("org.redisson.hibernate.CollectionTest$A.bs").getHitCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
A a2 = s.get(A.class, 1L);
|
||||
B b2 = a2.bs.iterator().next();
|
||||
assertThat(a2.bs.size()).isEqualTo(1);
|
||||
s.getTransaction().commit();
|
||||
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getDomainDataRegionStatistics("org.redisson.hibernate.CollectionTest$A.bs").getHitCount());
|
||||
|
||||
stats.logSummary();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
import org.hibernate.annotations.NaturalIdCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@NamedQueries(@NamedQuery(name = "testQuery", query = "from ItemReadWrite where name = :name"))
|
||||
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "item")
|
||||
@NaturalIdCache
|
||||
public class ItemReadWrite {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(generator = "increment")
|
||||
@GenericGenerator(name = "increment", strategy = "increment")
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@NaturalId
|
||||
private String nid;
|
||||
|
||||
@ElementCollection
|
||||
@JoinTable(name = "Entries", joinColumns = @JoinColumn(name="Item_id"))
|
||||
@Column(name = "entry", nullable = false)
|
||||
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "item_entries")
|
||||
private List<String> entries = new ArrayList<String>();
|
||||
|
||||
public ItemReadWrite() {
|
||||
}
|
||||
|
||||
public ItemReadWrite(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getNid() {
|
||||
return nid;
|
||||
}
|
||||
|
||||
public void setNid(String nid) {
|
||||
this.nid = nid;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<String> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
import org.hibernate.annotations.NaturalIdCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@NamedQueries(@NamedQuery(name = "testQuery", query = "from ItemTransactional where name = :name"))
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL, region = "item")
|
||||
@NaturalIdCache
|
||||
public class ItemTransactional {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(generator = "increment")
|
||||
@GenericGenerator(name = "increment", strategy = "increment")
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@NaturalId
|
||||
private String nid;
|
||||
|
||||
@ElementCollection
|
||||
@JoinTable(name = "Entries", joinColumns = @JoinColumn(name="Item_id"))
|
||||
@Column(name = "entry", nullable = false)
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL, region = "item_entries")
|
||||
private List<String> entries = new ArrayList<String>();
|
||||
|
||||
public ItemTransactional() {
|
||||
}
|
||||
|
||||
public ItemTransactional(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getNid() {
|
||||
return nid;
|
||||
}
|
||||
|
||||
public void setNid(String nid) {
|
||||
this.nid = nid;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<String> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.hibernate.query.Query;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.stat.Statistics;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class ReadWriteTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { ItemReadWrite.class};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration cfg) {
|
||||
super.configure(cfg);
|
||||
cfg.setProperty(Environment.DRIVER, org.h2.Driver.class.getName());
|
||||
cfg.setProperty(Environment.URL, "jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;");
|
||||
cfg.setProperty(Environment.USER, "sa");
|
||||
cfg.setProperty(Environment.PASS, "");
|
||||
cfg.setProperty(Environment.CACHE_REGION_PREFIX, "");
|
||||
cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
|
||||
|
||||
cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "true");
|
||||
cfg.setProperty(Environment.USE_QUERY_CACHE, "true");
|
||||
cfg.setProperty(Environment.CACHE_REGION_FACTORY, RedissonRegionFactory.class.getName());
|
||||
|
||||
cfg.setProperty("hibernate.cache.redisson.item.eviction.max_entries", "100");
|
||||
cfg.setProperty("hibernate.cache.redisson.item.expiration.time_to_live", "1500");
|
||||
cfg.setProperty("hibernate.cache.redisson.item.expiration.max_idle_time", "1000");
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
sessionFactory().getCache().evictAllRegions();
|
||||
sessionFactory().getStatistics().clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuery() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemReadWrite item = new ItemReadWrite("data");
|
||||
item.getEntries().addAll(Arrays.asList("a", "b", "c"));
|
||||
s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
Query<ItemReadWrite> query = s.getNamedQuery("testQuery");
|
||||
query.setCacheable(true);
|
||||
query.setCacheRegion("myTestQuery");
|
||||
query.setParameter("name", "data");
|
||||
item = query.uniqueResult();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getDomainDataRegionStatistics("myTestQuery").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
Query<ItemReadWrite> query2 = s.getNamedQuery("testQuery");
|
||||
query2.setCacheable(true);
|
||||
query2.setCacheRegion("myTestQuery");
|
||||
query2.setParameter("name", "data");
|
||||
item = query2.uniqueResult();
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getDomainDataRegionStatistics("myTestQuery").getHitCount());
|
||||
|
||||
stats.logSummary();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
package org.redisson.hibernate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.query.Query;
|
||||
import org.hibernate.stat.Statistics;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class TransactionalTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { ItemTransactional.class};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration cfg) {
|
||||
super.configure(cfg);
|
||||
cfg.setProperty(Environment.DRIVER, org.h2.Driver.class.getName());
|
||||
cfg.setProperty(Environment.URL, "jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;");
|
||||
cfg.setProperty(Environment.USER, "sa");
|
||||
cfg.setProperty(Environment.PASS, "");
|
||||
cfg.setProperty(Environment.CACHE_REGION_PREFIX, "");
|
||||
cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
|
||||
|
||||
cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "true");
|
||||
cfg.setProperty(Environment.USE_QUERY_CACHE, "true");
|
||||
cfg.setProperty(Environment.CACHE_REGION_FACTORY, RedissonRegionFactory.class.getName());
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
sessionFactory().getCache().evictAllRegions();
|
||||
sessionFactory().getStatistics().clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuery() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemTransactional item = new ItemTransactional("data");
|
||||
item.getEntries().addAll(Arrays.asList("a", "b", "c"));
|
||||
s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
Query query = s.getNamedQuery("testQuery");
|
||||
query.setCacheable(true);
|
||||
query.setCacheRegion("myTestQuery");
|
||||
query.setParameter("name", "data");
|
||||
item = (ItemTransactional) query.uniqueResult();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getDomainDataRegionStatistics("myTestQuery").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
Query query2 = s.getNamedQuery("testQuery");
|
||||
query2.setCacheable(true);
|
||||
query2.setCacheRegion("myTestQuery");
|
||||
query2.setParameter("name", "data");
|
||||
item = (ItemTransactional) query2.uniqueResult();
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getDomainDataRegionStatistics("myTestQuery").getHitCount());
|
||||
|
||||
stats.logSummary();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollection() {
|
||||
Long id = null;
|
||||
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemTransactional item = new ItemTransactional("data");
|
||||
item.getEntries().addAll(Arrays.asList("a", "b", "c"));
|
||||
id = (Long) s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemTransactional) s.get(ItemTransactional.class, id);
|
||||
assertThat(item.getEntries()).containsExactly("a", "b", "c");
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getDomainDataRegionStatistics("item_entries").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemTransactional) s.get(ItemTransactional.class, id);
|
||||
assertThat(item.getEntries()).containsExactly("a", "b", "c");
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getDomainDataRegionStatistics("item_entries").getHitCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNaturalId() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemTransactional item = new ItemTransactional("data");
|
||||
item.setNid("123");
|
||||
s.save(item);
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
Assert.assertEquals(1, stats.getDomainDataRegionStatistics("item").getPutCount());
|
||||
Assert.assertEquals(1, stats.getNaturalIdStatistics(ItemTransactional.class.getName()).getCachePutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemTransactional) s.bySimpleNaturalId(ItemTransactional.class).load("123");
|
||||
assertThat(item).isNotNull();
|
||||
s.delete(item);
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getDomainDataRegionStatistics("item").getHitCount());
|
||||
Assert.assertEquals(1, stats.getNaturalIdStatistics(ItemTransactional.class.getName()).getCacheHitCount());
|
||||
|
||||
sessionFactory().getStatistics().logSummary();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithRefreshThenRollback() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
Long id = null;
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
ItemTransactional item = new ItemTransactional( "data" );
|
||||
id = (Long) s.save( item );
|
||||
s.flush();
|
||||
s.getTransaction().commit();
|
||||
|
||||
Assert.assertEquals(1, stats.getDomainDataRegionStatistics("item").getPutCount());
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
item = (ItemTransactional) s.get(ItemTransactional.class, id);
|
||||
item.setName("newdata");
|
||||
s.update(item);
|
||||
s.flush();
|
||||
s.refresh(item);
|
||||
s.getTransaction().rollback();
|
||||
s.clear();
|
||||
s.close();
|
||||
|
||||
Assert.assertEquals(1, stats.getDomainDataRegionStatistics("item").getHitCount());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
hibernate.connection.driver_class=org.h2.Driver
|
||||
hibernate.connection.url=jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1
|
||||
hibernate.connection.username=sa
|
||||
hibernate.connection.password=
|
@ -0,0 +1,2 @@
|
||||
singleServerConfig:
|
||||
address: "redis://127.0.0.1:6379"
|
Loading…
Reference in New Issue