“在Shardingsphere框架中使用Postgres Jsonb数据”
这篇文章介绍如何在ShardingSphere框架中使用postgres jsonb类型的数据:
经过本地验证,ShardingSphere无法支持JPA和PostgreSQL Jsonb同时使用,如果同时使用会报
Can't infer the SQL type to use for an instance of com.fasterxml.jackson.databind.node.ObjectNode. Use setObject() with an explicit Types value to specify the type to use.
这种错误,为了支持Jsonb数据类型,只能使用SQL语句来操作包含Jsonb的表。
本文操作的对象是:
public class News implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "title")
private String title;
@Column(name = "author")
private String author;
@Column(name = "content", columnDefinition = "jsonb")
private String content;
}
这是Jpa定义的Repo类
@Repository
public interface NewsRepo extends JpaRepository<News, Long> {
}
这个类如果不扩展的话是不支持对news表的增删改查的,我们继承一个接口来扩展这个Repo:
public interface NewsRepoCustom {
News saveOne(News news);
}
然后让NewsRepo继承这个接口。 接下来我们需要自己实现扩展出来的接口,在Jpa框架下如果要执行自定义SQL,需要注入EntityManager这个对象。
@Component
public class NewsRepoImpl implements NewsRepoCustom {
@PersistenceContext
private EntityManager entityManager;
@Override
public News saveOne(final News news) {
return null;
}
}
PostgreSQL中向数据表插入jsonb数据,需要使用jsonb函数,如果向本文使用的news表插入数据,SQL应该是:
insert into news (title, author, content) values ('', '', ''::jsonb);
所以我们需要在NewsRepoImpl的saveOne方法中执行Raw SQL:
Session session = entityManager.unwrap(Session.class);
return session.doReturningWork(connection -> {
String sql = "insert into news(title, author, content) values (?, ?, ?::jsonb)";
PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
int paramIndex = 1;
ps.setString(paramIndex++, news.getTitle());
ps.setString(paramIndex++, news.getAuthor());
ps.setString(paramIndex, news.getContent());
ps.executeUpdate();
ResultSet result = ps.getGeneratedKeys();
while (result.next()) {
news.setId(result.getLong(1));
}
ps.close();
return news;
});
这样子就可以实现向数据表中插入jsonb类型的数据了。如果想要查看完整的例子,可以参考这个Github Repo。