NutzCN Logo
问答 Record 插入TIMESTAMP 类型为Null Postgresql报错。
发布于 2625天前 作者 qq_a6923084 4530 次浏览 复制 上一个帖子 下一个帖子
标签:

测试代码:

Record row = new Record();
row.set(".table","test");
row.set("createTime",new Timestamp(System.currentTimeMillis()));
row.set("updateTime",null);
dao.fastInsert(row);

log4j: 2017-07-14 10:02:18,162 [main] DEBUG org.nutz.dao.impl.sql.run.NutDaoExecutor - SQLException
org.postgresql.util.PSQLException: ERROR: column "updatetime" is of type timestamp without time zone but expression is of type character varying
  建议:You will need to rewrite or cast the expression.
  位置:450
	at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2161)
	at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1890)
	at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
	at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:559)
	at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:417)
	at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:410)
	at com.alibaba.druid.pool.DruidPooledPreparedStatement.execute(DruidPooledPreparedStatement.java:448)
	at org.nutz.dao.impl.sql.run.NutDaoExecutor._runPreparedStatement(NutDaoExecutor.java:261)
	at org.nutz.dao.impl.sql.run.NutDaoExecutor.exec(NutDaoExecutor.java:76)
	at org.nutz.dao.impl.DaoSupport$DaoExec.invoke(DaoSupport.java:249)
	at org.nutz.dao.impl.sql.run.NutDaoRunner.run(NutDaoRunner.java:64)
	at org.nutz.dao.impl.DaoSupport._exec(DaoSupport.java:204)
	at org.nutz.dao.impl.EntityOperator.exec(EntityOperator.java:50)
	at org.nutz.dao.impl.NutDao.fastInsert(NutDao.java:171)
	at com.gzx.hr.test.GzxHrTestMain$4.invoke(GzxHrTestMain.java:170)
	at com.gzx.hr.test.GzxHrTestMain$4.invoke(GzxHrTestMain.java:1)

跟踪问题,猜测原因是
EntityHolder中,猜测数据库类型null的情况直接当做varchar处理,导致实际插入执行的是

stat.setNull(i, Types.NULL);
非  stat.setNull(i, Types.TIMESTAMP);

            // 猜测一下数据库类型
            Jdbcs.guessEntityFieldColumnType(ef); // 做ColType.VARCHAT处理
            ef.setAdaptor(support.expert.getAdaptor(ef));
9 回复

那也推测不了实际类型吧?

用的 Record 对象插入数据 库 应该没有到 EntityHolder,删除这句看目的地row.set("updateTime",null);

public void setupEntityField(Connection conn, Entity<?> en) {...}
有进行过根据数据库实际字段来验证,但是没有验证字段类型。

很多情况是拼凑的数据,删除row.set("updateTime",null); 需要判定值是否为null 且字段类型等。框架解决不是更合理吗?

public void setupEntityField(Connection conn, Entity<?> en) {
        Statement stat = null;
        ResultSet rs = null;
        ResultSetMetaData rsmd = null;
        try {
            // 获取数据库元信息
            stat = conn.createStatement();
            rs = stat.executeQuery(createResultSetMetaSql(en));
            rsmd = rs.getMetaData();
            // 循环字段检查
            for (MappingField mf : en.getMappingFields()) {
                try {
					int ci = Daos.getColumnIndex(rsmd, mf.getColumnName());
					// 是否只读,如果人家已经是指明是只读了,那么就不要自作聪明得再从数据库里验证了
					// if (!mf.isReadonly() && rsmd.isReadOnly(ci))
					// mf.setAsReadonly();
					// 是否非空
					if (ResultSetMetaData.columnNoNulls == rsmd.isNullable(ci))
					    mf.setAsNotNull();
					// 枚举类型在数据库中的值
					if (mf.getTypeMirror().isEnum()) {
					    if (Daos.isIntLikeColumn(rsmd, ci)) {
					        mf.setColumnType(ColType.INT);
					    } else {
					        mf.setColumnType(ColType.VARCHAR);
					    }
					}
// TODO 是否可以验证实际字段类型呢??
				} catch (Exception e) {
					// TODO 需要log一下不?
				}
            }
        }

只要不包含枚举字段,已经不校验了.

似乎也没什么好办法, 要么扩展一下map插入的规则,可以声明类型信息

最简单的用 @hzl7652 方式删除该字段是有效的,但是有涉及面太广和需要多次判断的问题。
扩展map我觉得也可以,不过目前就发现Postgresql 的Timestamp类型有这个问题。
@wendal 还有个类似的问题,在Postgresql里varchar类型的不能有空格,设置的时候需要trim下也挺有意思的。

先报个issue吧, 得讨论怎么改

添加回复
请先登陆
回到顶部