For English only, other languages will not accept.
Before report a bug, make sure you have:
Please pay attention on issues you submitted, because we maybe need more details.
If no response more than 7 days and we cannot reproduce it on current information, we will close it.
Please answer these questions before submitting your issue. Thanks!
4.0.0-RC2
Sharding-JDBC

preparedStatement is not null
preparedStatement is null
when use EncryptPreparedStatement to batch operation, preparedStatement will not Initialization
@Keanhua can you show you code how to use EncryptPreparedStatement? Because I use the EncryptPreparedStatement and it works well, here is my code:

@Keanhua
when use EncryptPreparedStatement to batch operation...
Please show us the SQL and usage for EncryptPreparedStatement.
@betterjava @tristaZero

this is mycode by use the mybatis plus。
when i insert batch it occurred the NullPointerException。


I have the same problem,only use encryptDataSource by mybatis.
when mybatis prepare the statement, it will set the queryTimeout ,but the preparedStatement does not created at this time, and the NPE occured!



AbstractStatementAdapter:

EncryptPreparedStatement:

here is my config:
spring.shardingsphere.encrypt.encryptors.name_encryptor.type=aes
spring.shardingsphere.encrypt.tables.user_info.columns.name.plainColumn=name
spring.shardingsphere.encrypt.tables.user_info.columns.name.cipherColumn=name_encrypt
spring.shardingsphere.encrypt.tables.user_info.columns.name.encryptor=name_encryptor
spring.shardingsphere.props.query.with.cipher.comlum=true
spring.shardingsphere.props.sql.show=true
mybatis-version:
org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.2
springboot-version:
1.5.5
Hi, can you show us the content of settleCompanyService.saveBatch(). What's the action or sql of this function? @xiyelife
not only batch insert,the sigle insert occured too ,here is my sql:
encrypted columns: name,ident,mobile
t.mybatis.mapper.UserInfoMapper.insert : ==> Preparing: insert into user_info (cust_id, unique_id, name, ident, mobile, password, reg_time, modify_time, reg_source, reg_app_channel, reg_device_info, status, is_mobile_authed, complate_cust_info, time_inst, time_upd, has_checked) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, now() , ?, ?)
ShardingSphere-SQL : SQL: insert into user_info (cust_id, unique_id, name_encrypt,
ident_encrypt, mobile_encrypt, password,
reg_time, modify_time, reg_source,
reg_app_channel, reg_device_info, status,
is_mobile_authed, complate_cust_info, time_inst,
time_upd, has_checked, mobile, ident, name)
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, now(), ?, ?, ?, ?, ?)
code is:
UserInfo record = new UserInfo();
record.setMobile(mobile);
record.setName(TestLocalKmssdk.createName());
record.setPassword(oldPass);
int num = new Double(Math.random() * 1000000).intValue();
record.setIdent(ident + num);
record.setRegDeviceInfo(oldDev);
record.setModifyTime("111111");
record.setTimeInst(new Date());
record.setTimeUpd(new Date());
record.setRegSource("111");
record.setIsMobileAuthed("1");
userInfoMapper.insert(record);
@tristaZero
@xiyelife Thanks for your particular description. So great, i guess i get the point!
@xiyelife Thanks for your kind pr as well. Moreover, can you make this pr become better?
Actually, the solution in this pr can just stop NPE, but it is necessary to sovle it completely, so we should change our mind to stop NPE at beginning.
I suggest we can create a preparedStatement upon EncryptPreparedStatement is created, i.e, we should move preparedStatement = preparedStatementGenerator.createPreparedStatement(sqlUnit.getSql()); from execute() or executeUpdate() to all the constructors of EncryptPreparedStatement.
Therefore once EncryptPreparedStatement is created, the preparedStatement will be created as well, then NPE will never happen.
If you have other advices, please contact me, or maybe you can modify your kind pr to perfect it. 😉
Here are the related codes
public EncryptPreparedStatement(final EncryptConnection connection, final String sql) {
this.sql = sql;
preparedStatementGenerator = new EncryptPreparedStatementGenerator(connection);
}
---
@Override
public int executeUpdate() throws SQLException {
try {
SQLUnit sqlUnit = getSQLUnit(sql);
preparedStatement = preparedStatementGenerator.createPreparedStatement(sqlUnit.getSql());
replaySetParameter(preparedStatement, sqlUnit.getParameters());
return preparedStatement.executeUpdate();
} finally {
clearParameters();
}
}
@tristaZero ok ,that's what I thought at first. I'll try to modify my pr later.
And I found that the latest version of the code(RC3-SNAPSHOT) would incorrectly insert my original column like this:
SQLRewriteEngine Pre:
columnNames=[name, ident, is_mobile_authed, mobile, modify_time, password, reg_device_info, reg_source, time_inst, time_upd, mobile, ident, name]
parameters=[闵姐, 600xxx756, 1, 1xxx4, 111111, jpaxsdsewrwe123123f, jpatest, 111, 2019-09-05 15:27:47.77, 2019-09-05 15:27:47.77])]
name=闵姐
mobile=1xxx4
atfter SQLRewriteEngine:
SQLUnit(sql=insert into user_info (name_encrypt, ident_encrypt, is_mobile_authed, mobile_encrypt, modify_time, password, reg_device_info, reg_source, time_inst, time_upd, mobile, ident, name) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?), parameters=[*n/w+WpRwyeiTYgpM59dyF9g==, *i4sLpmagWmoLIiHZ5h7bt1kTeFpBZrxX8jgy/M8y0fU0=, 1, *mN6+s/ObMX0ZTcWp7pl9T6g==, 111111, jpaxsdsewrwe123123f, jpatest, 111, 2019-09-05 15:27:47.77, 2019-09-05 15:27:47.77, 闵姐, 600xxx756, 1xxx4])
name=1xxx4
mobile=闵姐
the two columns are interchanged!!
The data stored in the database are also interchanged.
The problem of interchanged column was solved at #2975 yesterday. Thanks, and wait for your pr. 😄
@xiyelife Hi, after my investigation, the similar problem also happens in ShardingPreparedStatement. If you're interested in it, can u consider this issue. Don't worry, it does not have deadline.
@tristaZero Hi, there are no incoming parameters to bind at the time of construction, which can cause the generation of EncryptInsertOptimizedStatement failed:

I think the problem should be more complicated......
Got it, maybe we can split this task to two small ones.
First, if preparedStatemnt == null in getRoutedStatements(), emptyList will be returned. This step will stop NPE, but set queryTime() actually is not executed, for there is no preparedStatement.
Second, we may cache the value of queryTime() in AbstractStatementAdapter.java. When executeUpdate() or execute() is called, at this time, we relay the action, i.e, setQueryTime().
What's your opinion? we can do first one, i think. @xiyelife
yeah, I think so, we can deal with the remaining parameters by your way, i.e maxRows,fetchSize and so on. @tristaZero
@xiyelife Hi, if first one is done, the second one, i think, there is a easier way to do.
As we said before, it is needed to cache the value of setQueryTime() and when call execute(), this operation will be really performed.
Currently, setQueryTime() in AbstractStatementAdapter.java has cached the value, here it is,
@SuppressWarnings("unchecked")
@Override
public final void setQueryTimeout(final int seconds) throws SQLException {
// cache the value
recordMethodInvocation(targetClass, "setQueryTimeout", new Class[] {int.class}, new Object[] {seconds});
forceExecuteTemplate.execute((Collection) getRoutedStatements(), new ForceExecuteCallback<Statement>() {
@Override
public void execute(final Statement statement) throws SQLException {
statement.setQueryTimeout(seconds);
}
});
}
So, we just call replayMethodsInvocation() in EncryptPreparedStatement when call execute() or executeUpdate().
That's all, how about you?
@tristaZero yeah, it would be better, and it would solve the ShardingPreparedStatement problem.
sorry,I was busy yesterday. I'm going to change my pr.
Most helpful comment
The problem of interchanged column was solved at #2975 yesterday. Thanks, and wait for your pr. 😄