在历史数据迁移中遇到的问题:原数据库中的某些字段使用了des加密,但是在新数据库中要求保存明文,如果不想通过程序刷表解决问题,就可以使用oracle的调用java方法功能。
1.查看oracle的版本,命令查看版本信息,获取oracle内置的jre版本。
SELECT * FROM V$VERSION;
我的数据库是oracle12c,对应的jre版本是java6,oracle内置的java版本较低,具体对应关系可以自行百度。当然你也可以找到oracle的安装目录,比如我的安装目录为: F:\app\Administrator\product\12.1.0\dbhome_1\jdk\jre,找到jre文件夹进入bin执行java -version。
2.java编码
获取到jre的版本之后,在IDE中修改默认JDK,更改为oracle对应版本,然后开始编码,比如我的加解密方法需要两个类组成,可以这样编写:
两个类结构如图,这两个类直接在src下面,通过DesUtilsTest类调用DesUtils类的decrypt方法。
两个类具体内容如下:
/**
* 加解密的方法调用类 DesUtilsTest.test()为调用方法
*/
public class DesUtilsTest {
public static void main(String[] args) {
System.out.println(test("0f2f735790e41b17;"));
}
public static String test(String data) {
try {
String msg = "";
DesUtils desUtils = new DesUtils();
String[] arr = data.split(";");
if (arr.length > 0) {
for (String str : arr) {
msg = msg + desUtils.decrypt(str, "UTF-8");
}
} else {
msg = desUtils.decrypt(data, "UTF-8");
}
return msg;
} catch (Exception e) {
return "异常";
}
}
}
import sun.misc.BASE64Decoder;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
/**
* 加解密工具类
*/
public class DesUtils {
public BASE64Decoder decoder = new BASE64Decoder();
public SecretKey getKey(String key) throws Exception {
DESedeKeySpec dks = new DESedeKeySpec(decoder.decodeBuffer(key));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
SecretKey securekey = keyFactory.generateSecret(dks);
return securekey;
}
public String decrypt(String text, String charset) throws Exception {
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(2, getKey("6eC/Shrj3F7W9x+F6Q1og29u9NpGYu/I"));
byte[] textBytes = parseHexStr2Byte(text);
byte[] bytes = cipher.doFinal(textBytes);
String decryptString = new String(bytes, charset);
return decryptString;
}
public byte[] parseHexStr2Byte(String hexStr) {
if (hexStr.length() < 1) {
return null;
} else {
byte[] result = new byte[hexStr.length() / 2];
for (int i = 0; i < hexStr.length() / 2; ++i) {
int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
result[i] = (byte) (high * 16 + low);
}
return result;
}
}
}
3.编译、打包
将这两个文件编译成class文件,然后执行cmd命令 jar -cvf DesUtilsTest.jar ./
命令执行成功后会在当前文件夹生成DesUtilsTest.jar文件
4.将jar包导入oracle中
首先把刚才生成的jar包放入C:\Users\MPF\Desktop\dljz-server文件夹下面(位置你随便放,我是为了省事) 打开cmd窗口,执行以下命令
-- 导入jar 导入成功后可以通过SQL查看: SELECT * FROM USER_JAVA_CLASSES;
loadjava -r -f -verbose -resolve -user 用户名/密码@//IP:1521/orcl C:\Users\MPF\Desktop\dljz-server\DesUtilsTest.jar
-- 重新上传时要先删除jar 再导入
dropjava -r -f -verbose -resolve -user 用户名/密码@//IP:1521/orcl C:\Users\MPF\Desktop\dljz-server\DesUtilsTest.jar
5.在oracle中创建函数
-- 创建函数
CREATE OR REPLACE FUNCTION "GETDECDATA"(DECDATA VARCHAR2) RETURN VARCHAR2 AS
LANGUAGE JAVA NAME 'DesUtilsTest.test(java.lang.String) return java.lang.String';
创建完成后就可以查询使用了
-- 查询解密后的数据
SELECT GETDECDATA(F_FZR), GETDECDATA(F_SFZH), GETDECDATA(F_JGMC) FROM TB_TEMP
注意事项:
1.oracle中函数调用的java方法必须是static修饰的。
2.在被调用的方法中,如果该方法还依赖其他类,那么其他类必须要new,而不是通过static使用类名调用(我使用类名+静态方法形式调用一直出错,也可能是我没有操作对,用new就没问题了)。
3.java类的包结构应该尽量简单,不要包裹太多层级,比如com.oracle.test.DesUtils,这样就比较长了,建议去除前面,直接使用DesUtils。
4.在调用过程中如果出现类似需要授权的操作,就根据他的提示用call调用一下,比如:
call dbms_java.grant_permission( 'DLJZ', 'SYS:java.lang.RuntimePermission', 'accessClassInPackage.sun.misc', '' )
最后:我测试过java文件、class文件都没有成功,只有jar成功了,可能之前是操作有问题,也请各位予以指正。