可以将 Ignite 用作现有数据库(例如 RDBMS 或 NoSQL 数据库,例如 Apache Cassandra 或 MongoDB)之上的缓存层。这个用例通过使用内存处理来加速底层数据库。
Ignite 提供与 Apache Cassandra 的开箱即用集成。对于其他没有现成集成的 NoSQL 数据库,您可以提供自己的CacheStore接口实现。
可以使用外部存储的两个主要用例包括:
-
现有数据库的缓存层。在这种情况下,您可以通过将数据加载到内存中来提高处理速度。您还可以将 SQL 支持引入没有它的数据库(当所有数据都加载到内存中时)。
-
您希望将数据持久保存在外部数据库中(而不是使用本机持久性)
读写策略
直读Read-Through和直写Write-Through
通读意味着如果数据在缓存中不可用,则从底层持久存储中读取数据。请注意,这仅适用于通过键值 API 进行的 get 操作;SELECT 查询从不读取外部数据库中的数据。loadCache()
要执行选择查询,必须通过调用该方法将数据从数据库预加载到缓存中。
直写意味着数据在缓存中更新时会自动持久化。所有的通读和通写操作都参与缓存事务,并作为一个整体提交或回滚。
后写缓存Write-Behind
在简单的直写模式下,每个 put 和 remove 操作都涉及对持久存储的相应请求;因此,更新操作的总持续时间可能相对较长。此外,密集的高速缓存更新率会导致极高的存储负载。
对于这种情况,您可以启用write-behind模式,其中更新操作是异步执行的。这种方法的关键概念是累积更新并将它们作为批量操作异步刷新到底层数据库。您可以基于基于时间的事件(数据条目可以驻留在队列中的最长时间受到限制)、队列大小的事件(当队列大小达到某个特定点时刷新队列)或这两者来触发数据刷新(以先发生者为准)。
关系型数据库集成
要将 RDBMS 用作底层存储,您可以使用以下实现之一CacheStore
。
-
CacheJdbcPojoStore
— 使用反射将对象存储为一组字段。如果您在现有数据库之上添加 Ignite 并希望使用基础表中的特定字段(或所有字段),请使用此实现。 -
CacheJdbcBlobStore
— 将对象以 Blob 格式存储在底层数据库中。当您将外部数据库用作持久存储并希望以简单格式存储数据时,此选项非常有用。
测试代码
在MySql中创建测试表,导入测试数据
-- ignite.PERSON definition
CREATE TABLE `PERSON` (
`id` int(11) NOT NULL,
`name` varchar(128) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO ignite.PERSON
(id, name)
VALUES(1, 'sn');
创建Java Bean,与MySql中的表做映射
class Person implements Serializable {
private static final long serialVersionUID = 0L;
private int id;
private String name;
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
创建测试Main
public class JdbcStoreDemo implements Serializable {
public static void main(String[] args) {
IgniteConfiguration igniteCfg = new IgniteConfiguration();
CacheConfiguration<Integer, Person> personCacheCfg = new CacheConfiguration<>();
personCacheCfg.setName("PersonCache");
personCacheCfg.setCacheMode(CacheMode.PARTITIONED);
personCacheCfg.setAtomicityMode(CacheAtomicityMode.ATOMIC);
personCacheCfg.setReadThrough(true);
personCacheCfg.setWriteThrough(true);
CacheJdbcPojoStoreFactory<Integer, Person> factory = new CacheJdbcPojoStoreFactory<>();
factory.setDialect(new MySQLDialect());
factory.setDataSourceFactory(new JDBCFactory());
// factory.setDataSourceFactory(new Factory<DataSource>() {
// @Override
// public DataSource create() {
// MysqlDataSource mysqlDataSrc = new MysqlDataSource();
// mysqlDataSrc.setURL("jdbc:mysql://192.168.165.43:3306/ignite");
// mysqlDataSrc.setUser("root");
// mysqlDataSrc.setPassword("1q2w3eROOT!");
// return mysqlDataSrc;
// }
// });
JdbcType personType = new JdbcType();
personType.setCacheName("PersonCache");
personType.setKeyType(Integer.class);
personType.setValueType(Person.class);
personType.setDatabaseTable("PERSON");
personType.setKeyFields(new JdbcTypeField(java.sql.Types.INTEGER, "id", Integer.class, "id"));
personType.setValueFields(new JdbcTypeField(java.sql.Types.INTEGER, "id", Integer.class, "id"));
personType.setValueFields(new JdbcTypeField(java.sql.Types.VARCHAR, "name", String.class, "name"));
factory.setTypes(personType);
personCacheCfg.setCacheStoreFactory(factory);
QueryEntity qryEntity = new QueryEntity();
qryEntity.setKeyType(Integer.class.getName());
qryEntity.setValueType(Person.class.getName());
qryEntity.setKeyFieldName("id");
Set<String> keyFields = new HashSet<>();
keyFields.add("id");
qryEntity.setKeyFields(keyFields);
LinkedHashMap<String, String> fields = new LinkedHashMap<>();
fields.put("id", "java.lang.Integer");
fields.put("name", "java.lang.String");
qryEntity.setFields(fields);
personCacheCfg.setQueryEntities(Collections.singletonList(qryEntity));
igniteCfg.setCacheConfiguration(personCacheCfg);
//igniteCfg.setClientMode(true);
// Classes of custom Java logic will be transferred over the wire from this app.
igniteCfg.setPeerClassLoadingEnabled(true);
// igniteCfg.setDeploymentMode(DeploymentMode.CONTINUOUS);
// Setting up an IP Finder to ensure the client can locate the servers.
// TcpDiscoveryMulticastIpFinder ipFinder = new TcpDiscoveryMulticastIpFinder();
// ipFinder.setAddresses(Collections.singletonList("127.0.0.1:47500..47509"));
// igniteCfg.setDiscoverySpi(new TcpDiscoverySpi().setIpFinder(ipFinder));
TcpDiscoveryMulticastIpFinder ipFinder = new TcpDiscoveryMulticastIpFinder();
ArrayList<String> strings = new ArrayList<>();
ipFinder.setAddresses(Collections.singletonList("127.0.0.1:47500..47509"));
ipFinder.setAddresses(strings);
igniteCfg.setDiscoverySpi(new TcpDiscoverySpi().setIpFinder(ipFinder));
// UriDeploymentSpi deploymentSpi = new UriDeploymentSpi();
// deploymentSpi.setUriList(Arrays.asList("file:/Users/wangkai/sourceFromGit/flink-sources/target"));
// igniteCfg.setDeploymentSpi(deploymentSpi);
// Starting the node
Ignite ignite = Ignition.start(igniteCfg);
//ignite.active();
// System.out.println(ignite.cacheNames());
IgniteCache<Integer, Person> personCache = ignite.cache("PersonCache");
Person person = personCache.get(3);
System.out.println(person);
// Person person1 = new Person();
// person1.setId(3);
// person1.setName("aaa");
// personCache.put(3,person1);
// Iterator<Cache.Entry<Integer, Person>> iterator = personCache.iterator();
// while (iterator.hasNext()){
// System.out.println(iterator.next().getValue());
// }
}
JDBCFactory类
import javax.cache.configuration.Factory;
import javax.sql.DataSource;
import java.io.Serializable;
public class JDBCFactory implements Factory<DataSource>, Serializable {
@Override
public DataSource create() {
MysqlDataSource mysqlDataSrc = new MysqlDataSource();
mysqlDataSrc.setURL("jdbc:mysql://127.0.0.1:3306/ignite");
mysqlDataSrc.setUser("root");
mysqlDataSrc.setPassword("xxx");
return mysqlDataSrc;
}
}