从 Spring 引导向 Cassandra 动态添加列
Add columns dynamically to Cassandra from Spring Boot
我正在尝试从 Spring 引导应用程序动态添加新列。比方说,每次事件 e 发生时,我想将一列添加到 Cassandra table 中,并具有定义明确的列名和类型。我试过这段代码:
@Query("alter table attributes.attributedata add ?0 ?1")
public void addColumn(String columnName, String dataType);
错误日志:
org.springframework.cassandra.support.exception.CassandraQuerySyntaxException: line 1:41 no viable alternative at input 'gac5' (alter table attributes.attributedata add ['gac]...); nested exception is com.datastax.driver.core.exceptions.SyntaxError: line 1:41 no viable alternative at input 'gac5' (alter table attributes.attributedata add ['gac]...)
at org.springframework.cassandra.support.CassandraExceptionTranslator.translateExceptionIfPossible(CassandraExceptionTranslator.java:132)
at org.springframework.cassandra.core.CqlTemplate.potentiallyConvertRuntimeException(CqlTemplate.java:946)
at org.springframework.cassandra.core.CqlTemplate.translateExceptionIfPossible(CqlTemplate.java:930)
at org.springframework.cassandra.core.CqlTemplate.translateExceptionIfPossible(CqlTemplate.java:912)
at org.springframework.cassandra.core.CqlTemplate.doExecute(CqlTemplate.java:278)
at org.springframework.cassandra.core.CqlTemplate.doExecute(CqlTemplate.java:559)
at org.springframework.cassandra.core.CqlTemplate.doExecute(CqlTemplate.java:549)
at org.springframework.cassandra.core.CqlTemplate.query(CqlTemplate.java:485)
at org.springframework.cassandra.core.CqlTemplate.query(CqlTemplate.java:510)
at org.springframework.cassandra.core.CqlTemplate.query(CqlTemplate.java:505)
at org.springframework.data.cassandra.core.CassandraTemplate.selectOne(CassandraTemplate.java:638)
at org.springframework.data.cassandra.core.CassandraTemplate.selectOne(CassandraTemplate.java:509)
at org.springframework.data.cassandra.repository.query.CassandraQueryExecution$SingleEntityExecution.execute(CassandraQueryExecution.java:104)
at org.springframework.data.cassandra.repository.query.CassandraQueryExecution$ResultProcessingExecution.execute(CassandraQueryExecution.java:143)
at org.springframework.data.cassandra.repository.query.AbstractCassandraQuery.execute(AbstractCassandraQuery.java:113)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:483)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:56)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
我也试过将整个查询存储到一个字符串中,然后直接将字符串放入值中,这样
@Query(value="?0")
但这也不管用。
这段代码工作得很好。如果从函数中获得的值未包含在单个引号中,则代码可以运行。
@Query("alter table attributes.attributedata add dummy text")
public void addColumn(String columnName, String dataType);
这有什么办法吗?请提出可能的替代方案。
您可以使用 CONCAT
尝试类似的操作
@Query("alter table attributes.attributedata add CONCAT('%',:columnNameDataType,'%')")
public void addColumn(String columnNameDataType);
勾选这个link
可以如代码所示创建一个集群对象,然后是执行查询的会话对象。要添加的列的名称和类型作为参数传递。
public void addColumn(String columnName, String columnType){
//Query
String query = "ALTER TABLE keyspace.tablename ADD " + columnName + " " + columnType;
//Creating Cluster object
Cluster cluster = Cluster.builder().addContactPoint("127.0.0.1").build();
//Creating Session object
Session session = cluster.connect();
//Executing the query
session.execute(query);
System.out.println("Column added");
}
为了优化代码,我们可以在应用程序启动时只创建一次会话对象。此类场景的实现如下:
private Session session;
@EventListener(ApplicationReadyEvent.class)
private void createSessionObject(){
//Creating Cluster object
Cluster cluster = Cluster.builder().addContactPoint("127.0.0.1").build();
//Creating Session object
Session session = cluster.connect();
}
public void addColumn(String columnName, String columnType){
//Query
String query = "ALTER TABLE keyspace.tablename ADD " + columnName + " " + columnType;
if(session == null){
createSessionObject();
}
//Executing the query
session.execute(query);
System.out.println("Column added");
}
我正在尝试从 Spring 引导应用程序动态添加新列。比方说,每次事件 e 发生时,我想将一列添加到 Cassandra table 中,并具有定义明确的列名和类型。我试过这段代码:
@Query("alter table attributes.attributedata add ?0 ?1")
public void addColumn(String columnName, String dataType);
错误日志:
org.springframework.cassandra.support.exception.CassandraQuerySyntaxException: line 1:41 no viable alternative at input 'gac5' (alter table attributes.attributedata add ['gac]...); nested exception is com.datastax.driver.core.exceptions.SyntaxError: line 1:41 no viable alternative at input 'gac5' (alter table attributes.attributedata add ['gac]...)
at org.springframework.cassandra.support.CassandraExceptionTranslator.translateExceptionIfPossible(CassandraExceptionTranslator.java:132)
at org.springframework.cassandra.core.CqlTemplate.potentiallyConvertRuntimeException(CqlTemplate.java:946)
at org.springframework.cassandra.core.CqlTemplate.translateExceptionIfPossible(CqlTemplate.java:930)
at org.springframework.cassandra.core.CqlTemplate.translateExceptionIfPossible(CqlTemplate.java:912)
at org.springframework.cassandra.core.CqlTemplate.doExecute(CqlTemplate.java:278)
at org.springframework.cassandra.core.CqlTemplate.doExecute(CqlTemplate.java:559)
at org.springframework.cassandra.core.CqlTemplate.doExecute(CqlTemplate.java:549)
at org.springframework.cassandra.core.CqlTemplate.query(CqlTemplate.java:485)
at org.springframework.cassandra.core.CqlTemplate.query(CqlTemplate.java:510)
at org.springframework.cassandra.core.CqlTemplate.query(CqlTemplate.java:505)
at org.springframework.data.cassandra.core.CassandraTemplate.selectOne(CassandraTemplate.java:638)
at org.springframework.data.cassandra.core.CassandraTemplate.selectOne(CassandraTemplate.java:509)
at org.springframework.data.cassandra.repository.query.CassandraQueryExecution$SingleEntityExecution.execute(CassandraQueryExecution.java:104)
at org.springframework.data.cassandra.repository.query.CassandraQueryExecution$ResultProcessingExecution.execute(CassandraQueryExecution.java:143)
at org.springframework.data.cassandra.repository.query.AbstractCassandraQuery.execute(AbstractCassandraQuery.java:113)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:483)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:56)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
我也试过将整个查询存储到一个字符串中,然后直接将字符串放入值中,这样
@Query(value="?0")
但这也不管用。
这段代码工作得很好。如果从函数中获得的值未包含在单个引号中,则代码可以运行。
@Query("alter table attributes.attributedata add dummy text")
public void addColumn(String columnName, String dataType);
这有什么办法吗?请提出可能的替代方案。
您可以使用 CONCAT
尝试类似的操作@Query("alter table attributes.attributedata add CONCAT('%',:columnNameDataType,'%')")
public void addColumn(String columnNameDataType);
勾选这个link
可以如代码所示创建一个集群对象,然后是执行查询的会话对象。要添加的列的名称和类型作为参数传递。
public void addColumn(String columnName, String columnType){
//Query
String query = "ALTER TABLE keyspace.tablename ADD " + columnName + " " + columnType;
//Creating Cluster object
Cluster cluster = Cluster.builder().addContactPoint("127.0.0.1").build();
//Creating Session object
Session session = cluster.connect();
//Executing the query
session.execute(query);
System.out.println("Column added");
}
为了优化代码,我们可以在应用程序启动时只创建一次会话对象。此类场景的实现如下:
private Session session;
@EventListener(ApplicationReadyEvent.class)
private void createSessionObject(){
//Creating Cluster object
Cluster cluster = Cluster.builder().addContactPoint("127.0.0.1").build();
//Creating Session object
Session session = cluster.connect();
}
public void addColumn(String columnName, String columnType){
//Query
String query = "ALTER TABLE keyspace.tablename ADD " + columnName + " " + columnType;
if(session == null){
createSessionObject();
}
//Executing the query
session.execute(query);
System.out.println("Column added");
}