I have the following user info object mapped to a table "user_info" in my keyspace "data_collection". I have created the "user_info" table in my cassandra database. I am using spring data cassandra for connecting to cassandra database from JAVA and the spring annotations as below.
#Table(name="user_info",keyspace="data_collection", caseSensitiveKeyspace = false,caseSensitiveTable = false)
public class UserInfo {
#PartitionKey
private UUID id;
#PrimaryKeyColumn
private String email;
private int phone;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public int getPhone() {
return phone;
}
public void setPhone(int phone) {
this.phone = phone;
}
}
I am using the following code to insert a record into my "user_info" table.
#Autowired
CassandraTemplate cassandraTemplate;
public void saveUserInfo(UserInfo userInfo){
logger.debug("userInfo "+new Gson().toJson(userInfo));
String email = userInfo.getEmail();
Select select = QueryBuilder.select().from("user_info");
select.where(QueryBuilder.eq("email", email));
logger.debug("Query "+select.toString());
UserInfo existingUser = cassandraTemplate.selectOne(select, UserInfo.class);
if(existingUser!=null){
cassandraTemplate.update(userInfo);
}
else{
cassandraTemplate.insert(userInfo);
}
}
My selectOne is working properly whereas during insert I am getting the following exception. I have clearly mapped the UserInfo.java class to the table name "user_info" using annotation above. I don't know why the insert is trying to happen to the table "userinfo".
org.springframework.cassandra.support.exception.CassandraInvalidQueryException: unconfigured columnfamily userinfo; nested exception is com.datastax.driver.core.exceptions.InvalidQueryException: unconfigured columnfamily userinfo
at org.springframework.cassandra.support.CassandraExceptionTranslator.translateExceptionIfPossible(CassandraExceptionTranslator.java:128)
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.execute(CqlTemplate.java:1333)
at org.springframework.data.cassandra.core.CassandraTemplate.doUpdate(CassandraTemplate.java:895)
at org.springframework.data.cassandra.core.CassandraTemplate.update(CassandraTemplate.java:537)
at org.springframework.data.cassandra.core.CassandraTemplate.update(CassandraTemplate.java:532)
Please find below the description of the table in cassandra.
CREATE TABLE user_info (
name text,
email text,
phone int
PRIMARY KEY ((email))
) WITH
bloom_filter_fp_chance=0.010000 AND
caching='KEYS_ONLY' AND
comment='' AND
dclocal_read_repair_chance=0.100000 AND
gc_grace_seconds=864000 AND
index_interval=128 AND
read_repair_chance=0.000000 AND
replicate_on_write='true' AND
populate_io_cache_on_flush='false' AND
default_time_to_live=0 AND
speculative_retry='99.0PERCENTILE' AND
memtable_flush_period_in_ms=0 AND
compaction={'class': 'SizeTieredCompactionStrategy'} AND
compression={'sstable_compression': 'LZ4Compressor'};
Quick update : I just tried saving another class Test.java. It was mapped to a table "test_info". I got the following error
org.springframework.cassandra.support.exception.CassandraInvalidQueryException: unconfigured columnfamily test; nested exception is com.datastax.driver.core.exceptions.InvalidQueryException: unconfigured columnfamily test
at org.springframework.cassandra.support.CassandraExceptionTranslator.translateExceptionIfPossible(CassandraExceptionTranslator.java:128)
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.execute(CqlTemplate.java:1323)
at org.springframework.data.cassandra.core.CassandraTemplate.doInsert(CassandraTemplate.java:708)
at org.springframework.data.cassandra.core.CassandraTemplate.insert(CassandraTemplate.java:290)
at org.springframework.data.cassandra.core.CassandraTemplate.insert(CassandraTemplate.java:285)
I am just wondering if my Java class name and the table name in cassandra should always be the same. Because its looking for the columnfamily "test" instead of "test_info" which I have specified in the #Table annotation.
Below is the description of my keyspace
CREATE KEYSPACE data_collection WITH replication = {
'class': 'SimpleStrategy',
'replication_factor': '3'
};
EDIT - SOLVED :
I found the solution based on the conversation with #pinkpanther.
I had imported com.datastax.driver.mapping.annotations.Table instead of org.springframework.data.cassandra.mapping.Table which is why it didn't honor the table name mapping. Thanks for your help.
The problem might be with the package import of Table, Spring Data Cassandra needs org.springframework.data.cassandra.mapping.Table. Replace the imported com.datastax.driver.mapping.annotations.Table with it.
Related
Intending to get the name of the table that was audited. Hopefully maybe by taking the object which is sent to revision info before it writes. Is there a way to do that.
#Entity
#RevisionEntity
#Table(name = "revision_info")
public class revision_info{
#Column(name = "tableName", length=36)
private String tableName=getTableName();
public revision_info() {
}
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
I'm terribly sorry if I can't start another post which is connected to my previous one but my question is somewhat different.
I noticed that I really can save new data in my database as long as I never added data to the database by using the line spring.datasource.initialization-mode=always in my application.properties and made a data.sql file with a few insert statements. Once I insert the data using that file, I can access the data and show it to the user, but I can't create any new data because I get the following error
ERROR: duplicate key value violates unique constraint "joke_pkey"
Detail: Key (id)=(1) already exists.
Does anyone know how to help me with this? I'm doing an interview task and I am meant to first import data using the data.sql file and then later add some more data.
The post with my code is here:
Spring Boot using save never inserts a row inside of a Postgresql table
EDIT - someone recommended adding my code here directly and saying what I've tried.
I have tried to initialize the database with the application properties the way they are, then restarting the app but without the last line, and setting the spring.jpa.hibernate.ddl-auto to none. But even so, it didn't work. I genuinely expected it to work like that. Because if the table is empty and I fill it in using the functions I created, everything works like a charm, even after restarting the server (id keep the ring.jpa.hibernate.ddl-auto to none again to keep the data from being deleted)
I have also tried simply changing the GenerationType.AUTO to GenerationType.TABLE strategy in my Joke class, but that didn't seem to change anything either.
application.properties :
spring.datasource.url=jdbc:postgresql://localhost:5432/flyway_demo
spring.datasource.username=bob
spring.datasource.password=bob123
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=create
spring.datasource.initialization-mode=always
My Web Controller that has the post function:
#PostMapping("/post")
public String insertJoke(JokeForm jokeForm) {
int categoryid = jokeForm.getCategoryId();
String content = jokeForm.getContent();
databasController.insert(categoryid, content);
return "redirect:/";
}
My DBController whose insert function is being called
public Joke insert(int categoryid, String content) {
return jokeRepository.save(new Joke(categoryid, content));
}
Most of my Joke data class:
#Entity
public class Joke {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(columnDefinition = "serial")
private Long id;
#NotNull
#Column(name = "category_id_FK")
private long categoryId;
#NotBlank
private String content;
#Column(columnDefinition = "integer default 0")
private int likes = 0;
#Column(columnDefinition = "integer default 0")
private int dislikes = 0;
public Joke() {
}
public Joke(long categoryid, String content) {
this.setCategoryid(categoryid);
this.setContent(content);
}
// id
public Long getId() {
return this.id;
}
// id
public void setId(Long id) {
this.id = id;
}
// categoryid
public long getCategoryid() {
return this.categoryId;
}
public void setCategoryid(long categoryid) {
this.categoryId = categoryid;
}
// content
public String getContent() {
return this.content;
}
public void setContent(String content) {
this.content = content;
}
// likes
public int getLikes() {
return this.likes;
}
public void setLikes(int likes) {
this.likes = likes;
}
// dislikes
public int getDislikes() {
return this.dislikes;
}
public void setDislikes(int dislikes) {
this.dislikes = dislikes;
}
}
Joke Repository:
#Repository
public interface JokeRepository extends JpaRepository<Joke, Integer> {
Joke findById(long id);
List<Joke> findByCategoryid(int categoryid);
}
It seems that all you need to do is change GenerationType.AUTO to GenerationType.IDENTITY.
Reason behind this is the sequence, which might be out of sync if you use AUTO. Because then hibernate uses its own sequence instead of the one postgres creates when using serial.
Im using loacalstack with dynamodb setup. Iv a table with two columns, an Id and a name column. Im struggling to query the table by 'name' using DynamoDBMapper. Below is a snippet of my setup
entity >
#AllArgsConstructor
#NoArgsConstructor
#DynamoDBTable(tableName = "my-table")
public class Table {
private String id;
private String name;
#DynamoDBHashKey(attributeName = "id")
#DynamoDBAutoGeneratedKey
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#DynamoDBAttribute
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#query >
public Table getByName(String name) {
return dynamoDBMapper.load(Table.class, name);
}
aws dynamodb create-table --endpoint-url=http://localstack:4569 --table-name my-table \
--attribute-definitions AttributeName=id,AttributeType=S AttributeName=name,AttributeType=S \
--key-schema AttributeName=id,KeyType=HASH AttributeName=name,KeyType=RANGE \
Any help appreciated
Obviously you cannot query the table by name as it is not the partition/hash key. Either you can use scan or you should state name as a GSI field and then query it. Scan command would be like:
dynamoDBMapper.scan(Table.class, new DynamoDBScanExpression());
The above command will scan the entire table. Read about DynamoDBScanExpression here to see how you can filter it with a specific name.
You can add a filter like on name like:
public Table getByName(String name) {
DynamoDBScanExpression scanExpression = new DynamoDBScanExpression();
scanExpression.addFilterCondition("name", new Condition()
.withComparisonOperator(ComparisonOperator.EQ)
.withAttributeValueList(new AttributeValue().withS(name)));
dynamoDBMapper.scan(Table.class, scanExpression);
}
I'm following the Cassandra java object mapper tutorial on Datastax website.
and while defining accessors
#Query("SELECT * FROM testks.user ")
Result<User> getAll();
running this query give me a
com.datastax.driver.core.exceptions.InvalidQueryException: Some partition key parts are missing: id
Looking around it seems that you cannot query in cassandra without providing a partition key. Is that the case? This seems like a strange requirement. If I want a select all query, how would I go about doing that?
the table is defined as
CREATE TABLE testks.user (
id text PRIMARY KEY,
name text
)
You didn't provide many details. if you follow these below steps you shouldn't get any error
You should define the user model like below
User.java
#Table(name = "user")
public class User {
#PartitionKey
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "User{" + "id=" + id + ", name=" + name + '}';
}
}
And Repository like below
UserAccessor.java
#Accessor
public interface UserAccessor {
#Query("SELECT * FROM user")
Result<User> getAll();
}
Here is how you can use the repository
Main.Java
public static void main(String[] args) {
try (Cluster cluster = Cluster.builder().addContactPoints("127.0.0.1").withCredentials("cassandra", "cassandra").build(); Session session = cluster.connect("test")) {
MappingManager manager = new MappingManager(session);
UserAccessor userAccessor = manager.createAccessor(UserAccessor.class);
System.out.println(userAccessor.getAll().all());
}
}
My DB contain User table with same named fields in class User.
I still have a problem with #Column annotation: Intellij IDEA stresses the name of the column.
DBTable
CREATE TABLE "user"
(
email character varying,
login character varying NOT NULL,
password character varying NOT NULL,
name character varying NOT NULL,
id_user numeric NOT NULL,
CONSTRAINT user_pkey PRIMARY KEY (login, password, id_user),
CONSTRAINT user_email_key UNIQUE (email)
)
Why this exception of syntax?? I have the same named table
root cause
org.postgresql.util.PSQLException: ERROR: syntax error at or near "User"
Position: 13
org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2198)
org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1927)
org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:561)
org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:419)
org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:365)
org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:133)
org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:58)
org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3067)
org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3509)
org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:88)
org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:377)
org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:369)
org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:286)
org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:339)
org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1234)
org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:404)
org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
com.classes.UserDB.registerUser(UserDB.java:17)
com.servlets.Registration.doPost(Registration.java:29)
javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
User class
package com.DB;
import javax.persistence.*;
#Entity
public class User {
#Lob
private String email;
#Lob
private String login;
#Lob
private String password;
#Lob
private String name;
#Id
#GeneratedValue
private int id_user;
public int getId_user() {
return id_user;
}
public void setId_user(int id_user) {
this.id_user = id_user;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User getUserFromBase(){
return this;
}
}
How it resolve?
user is a reserved word and table with name user can not be created.
try adding #Table(name="USER_TABLE") after #Entity to change table name.
sorry haven`t read that carefully. it seems u already have a table named "USER". that's the problem with oracle
"user" is a reserved word in PostgreSQL and it's usually not a good idea use reserved words for tables or columns.
If you want to save yourself a lot of trouble use a different name. users, user_acount.
also would change the class name for the same as table.
put #Table(name="USERS") annotation:
#Entity
#Table(name="users")
public class Users {
}