无比的兴奋,新版本的Bing支持国际版,这样就可以更好的检索国外的资料了。Oracle在Centos7中连接局域网内的速度很慢的问题,终于找到问题的原因了,当然可能还会存在其他问题,本文考虑两个:
(1)代理问题
ProxySelector.setDefault(null);
在开始连接数据库前调用,我开始的时候感觉有效,过一段时间就没有效果了,任然很慢,甚至第一次连接是失败的。
(2)安全随机数问题
后面继续检索(bing国际版),发现找到了问题:安全随机数问题(PRNG)。
经过测试,发现,的确,Windows系统上和Linux系统上,执行的时间不一样,代码如下:
long start = (Calendar.getInstance().getTimeInMillis());
System.out.println("Ok: " + SecureRandom.getInstance("SHA1PRNG").nextLong());
System.out.println(Calendar.getInstance().getTimeInMillis() - start);
Windows上执行,第一次在:60ms左右,后面该函数执行时间在1ms以内;而CentOS7 + OpenJDK 1.8,第一次在4800ms左右,后面函数执行时间在1ms以内。这个现象和连接Oracle第一次很慢很相似。
如何提高速度呢?stackflow上建议增加参数:
-Djava.security.egd=file:/dev/urandom
// 或(建议使用下面)
-Djava.security.egd=file:/dev/./urandom
通过增加该参数执行程序,发现,第一次执行时间在CentOS机器上只有39ms!
当然,专家说,这样得到的随机数是不安全的!
为什么不安全?其实随机数是一种可重复算法,给定随机数种子的情况下,随机数每一次的随机数应该相同的(与字面定义不同),为了获得真正的随机数,随机种子必需真正的随机!所以,这里面实现随机数的方法就有多种了,比如通过访问服务器获得随机数种子,或者收集系统特定的随机信息得到随机数种子,总之,这个过程需要时间……为了安全,他们还说,如果主板有随机数硬件,那就可以用这个……可是这个真不懂!
总之,在内网环境下,连接一下数据库,我觉得一般般的安装就够了,对不!影响启动数据可不行,尤其是调试程序的时候。测试代码如下,有兴趣的朋友可以测试一下自己的机器是不是这个问题:
OracleConnTest.java
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.URI;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.sqlException;
import java.sql.Statement;
import java.util.Calendar;
import java.util.List;
public class OracleConnTest {
public static void main(String[] args){
try {
ProxySelector selector = ProxySelector.getDefault();
List<Proxy> lstProxies = selector.select(URI.create("socket://10.0.0.10:1521"));
if (lstProxies != null){
for (Proxy proxy : lstProxies){
System.out.println(proxy.address().toString() + "," + proxy.type());
}
}
ProxySelector.setDefault(null);
lstProxies = selector.select(URI.create("socket://10.0.0.10:1521"));
if (lstProxies != null){
for (Proxy proxy : lstProxies){
System.out.println(proxy.address().toString() + "," + proxy.type());
}
}
long start;
start = Calendar.getInstance().getTimeInMillis();
Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
System.out.println("time elpase in get forname action:" + (Calendar.getInstance().getTimeInMillis() - start));
start = Calendar.getInstance().getTimeInMillis();
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@10.0.0.10:1521:irobot","robotservice","robotservice");
System.out.println("time elpase in get connection action:" + (Calendar.getInstance().getTimeInMillis() - start));
start = Calendar.getInstance().getTimeInMillis();
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("select 10 from dual");
System.out.println("time elpase in get data action:" + (Calendar.getInstance().getTimeInMillis() - start));
while(rs.next()){
System.out.print("must be 10:" + rs.getInt(1));
}
start = Calendar.getInstance().getTimeInMillis();
rs.close();
st.close();
conn.close();
System.out.println("time elpase in get close action:" + (Calendar.getInstance().getTimeInMillis() - start));
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (sqlException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
执行方法如下: java -cp .:./ojdbc6.jar OracleConnTest java -cp .:./ojdbc6.jar -Djava.security.egd=file:/dev/./urandom OracleConnTest