`

自己写的一个数据库模板类,可以直接操作封装好的数据对象类

阅读更多
package com.drug.db;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * 自己写的一个数据库工具类,希望可以封装所有的数据库操作
 * 直接对封装好的数据库对象javaBean进行操作
 * 
 * 数据库中表中的字段名必须首字母大写
 * 封装好的数据对象类javaBean中的变量必须和数据库表中的字段相对应,(首字母不用大写)
 * 
 * 这样以后修改数据库,只需要对应的修改一下数据对象类javaBean就行了,呵呵
 * 
 * 本人java还在自学中,望大家多多指正
 */
public class DBUtil {

    /**
     * 方 法 名: getTableRowCount
     * 功能描述: 获取表的行数
     * 输入参数:  tableName:表名
     * 返 回 值: int
     * 编 码 人:  zmj
     * 编码时间:  2010-2-8 上午11:10:26
     */
    public int getTableRowCount(String tableName) {
        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;
        int rowCount = -1;
        try {
            String sql = "select * from " + tableName;
            con = getCon();
            pst = con.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE,
                    ResultSet.CONCUR_READ_ONLY);
            rs = pst.executeQuery();
            rs.last();
            rowCount = rs.getRow();
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            close(con, pst, rs);
        }
        return rowCount;
    }

    /**
     * 方 法 名:hasElem
     * 功能描述:判断表中是否含有该元素
     * 输入参数: tableName:表名,keyName:查询的键值,key用来查询的键
     * 返 回 值: boolean
     * 编 码 人:  zmj
     * 编码时间:  2010-2-20 上午10:26:33
     */
    public boolean hasElem(String tableName, String keyName, Object key) {
        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;
        String sql = "select * from " + tableName + " where "
                + firstUpper(keyName) + "=?";
        try {
            con = getCon();
            pst = con.prepareStatement(sql);
            setObject(pst, 1, key);
            rs = pst.executeQuery();
            if (rs.next()) {
                return true;
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            close(con, pst, rs);
        }

        return false;
    }

    /**
     * 方 法 名:getTableElem
     * 功能描述: 获取数据库中一个表中的全部数据
     * 输入参数:tableName:表名,beanName:用来封闭的javaBean
     * 返 回 值: ArrayList<Object>
     * 编 码 人:  zmj
     * 编码时间:  2010-2-20 上午08:16:52
     */
    public ArrayList<Object> getTableElem(String tableName, String beanName) {
        return getElemList(tableName, beanName, 1, -1);
    }

    /***
     * 方 法 名:getTable 
     * 功能描述:获取数据库中一个表中的数据 
     * 输入参数:tableName:表名,beanName:用来封装的javaBean,offset:偏移量,count:取出的记录条数,为-1时表示全部
     * 返 回值:ArrayList<Object> 
     * 编 码 人: zmj 
     * 编码时间: 2010-2-8
     * **/
    public ArrayList<Object> getElemList(String tableName, String beanName,
            int offset, int count) {
        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;
        ArrayList<Object> rs_list = new ArrayList<Object>();
        try {
            String sql = "select * from " + tableName;
            con = getCon();
            pst = con.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE,
                    ResultSet.CONCUR_READ_ONLY);
            rs = pst.executeQuery();
            String[] paramName = tableColName(rs);
            Class<?> beanClass = Class.forName(beanName);
            if (offset > 1)
                rs.absolute(offset - 1);
            else if (offset < 0 && offset != -1)
                return rs_list;
            while (rs.next() && (count == -1 || count-- > 0)) {
                Object bean = beanClass.newInstance();
                saveBean(bean, rs, paramName);
                rs_list.add(bean);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } finally {
            close(con, pst, rs);
        }
        return rs_list;
    }

    /**
     * 方 法 名:fuzzySearch
     * 功能描述: 进行模糊查询
     * 输入参数: tableName:表名,beanName:用来封装的javaBean,
            keyName:查询的键值,key用来查询的键,offset:偏移量,count:返回的最大个数,-1表示全部
     * 返 回 值: ArrayList<Object>
     * 编 码 人:  zmj
     * 编码时间:  2010-2-8 下午01:44:23
     */
    public ArrayList<Object> fuzzySearch(String tableName, String beanName,
            String fuzzyKeyName, String fuzzyKey, Object[][] key, int offset,
            int count) {
        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;
        ArrayList<Object> rs_list = new ArrayList<Object>();
        try {
            String sql = "select * from " + tableName + " where "
                    + firstUpper(fuzzyKeyName) + " like ?";
            for (int i = 0; i < key.length; i++) {
                if (key[i].length == 2) {
                    sql += " and " + firstUpper((String) key[i][0]) + "=?";
                }
            }
            con = getCon();
            pst = con.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE,
                    ResultSet.CONCUR_READ_ONLY);
            pst.setObject(1, "%" + fuzzyKey + "%");
            for (int i = 0; i < key.length; i++) {
                if (key[i].length == 2) {
                    this.setObject(pst, i + 2, key[i][1]);
                }
            }
            rs = pst.executeQuery();
            String[] paramName = tableColName(rs);
            Class<?> beanClass = Class.forName(beanName);
            if (offset > 1)
                rs.absolute(offset - 1);
            else if (offset < 0 && offset != -1)
                return rs_list;
            while (rs.next() && (count == -1 || count-- > 0)) {
                Object bean = beanClass.newInstance();
                saveBean(bean, rs, paramName);
                rs_list.add(bean);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } finally {
            close(con, pst, rs);
        }
        return rs_list;
    }

    /***
     * 方 法 名:getElem 
     * 功能描述:获取数据库中一个表中的一条记录 
     * 输入参数:tableName:表名,beanName:javaBean的名字 
     * 返 回 值:Object 
     * 编 码 人: zmj 
     * 编码时间: 2010-2-8
     * @throws SQLException 
     * **/
    public Object getElem(String tableName, String keyName, Object key,
            String beanName) {
        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;
        String sql = "select * from " + tableName + " where "
                + firstUpper(keyName) + "=?";
        String[] paramName = null;
        try {
            con = getCon();
            pst = con.prepareStatement(sql);
            setObject(pst, 1, key);
            rs = pst.executeQuery();
            paramName = tableColName(rs);
            Class<?> beanClass;
            beanClass = Class.forName(beanName);
            Object bean = null;
            bean = beanClass.newInstance();
            if (rs.next()) {
                saveBean(bean, rs, paramName);
            }
            return bean;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } finally {
            close(con, pst, rs);
        }

        return null;
    }

    /***
     * 方 法 名:insert 
     * 功能描述:将JavaBean添加到数据库表table中 
     * 输入参数: tableName:表名,bean:javaBean
     * 返 回 值:int
     * 编 码 人: zmj 
     * 编码时间: 2010-2-8
     * **/
    public int insert(String tableName, Object bean) {
        Connection con = null;
        PreparedStatement pst = null;
        StringBuilder sql = new StringBuilder("insert into " + tableName + "(");
        try {
            Object[][] beanObj = bean2Array(bean);
            int n = beanObj.length;
            if (n < 1) {
                return 0;
            }
            for (int i = 0; i < n; i++) {
                if (i != 0)
                    sql.append(",");
                sql.append(beanObj[i][0]);
            }
            sql.append(") values(");
            for (int i = 0; i < n; i++) {
                if (i != 0)
                    sql.append(",");
                sql.append("?");
            }
            sql.append(")");
            con = getCon();
            pst = con.prepareStatement(sql.toString());
            for (int i = 0; i < n; i++) {
                setObject(pst, i + 1, beanObj[i][1]);
            }
            return pst.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } finally {
            close(con, pst);
        }
        return 0;
    }

    /**
     * 方 法 名:updateElem
     * 功能描述: 更新表中的一个元素
     * 输入参数: tableName,keyName,key,bean
     * 返 回 值: int
     * 编 码 人:  zmj
     * 编码时间:  2010-2-8 上午11:30:18
     */
    public int updateElem(String tableName, String keyName, Object key,
            Object bean) {
        Connection con = null;
        PreparedStatement pst = null;
        StringBuilder sql = new StringBuilder("update " + tableName + " set ");
        try {
            Object[][] beanObj = bean2Array(bean);
            int n = beanObj.length;
            if (n < 1) {
                return 0;
            }
            for (int i = 0; i < n; i++) {
                if (i != 0)
                    sql.append(",");
                sql.append(beanObj[i][0] + "=?");
            }
            sql.append(" where " + firstUpper(keyName) + "=?");
            con = getCon();
            pst = con.prepareStatement(sql.toString());
            int i = 0;
            for (; i < n; i++) {
                setObject(pst, i + 1, beanObj[i][1]);
            }
            setObject(pst, i + 1, key);
            return pst.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } finally {
            close(con, pst);
        }
        return 0;
    }

    /**
     * 方 法 名: deleteElem
     * 功能描述: 删除表中的一条记录
     * 输入参数:  tableName:表名, keyName:键名 key:键值
     * 返 回 值: int
     * 编 码 人:  zmj
     * 编码时间:  2010-2-8 下午01:47:08
     */
    public int deleteElem(String tableName, String keyName, Object key) {
        Connection con = null;
        PreparedStatement pst = null;
        StringBuilder sql = new StringBuilder("delete from " + tableName);
        try {
            sql.append(" where " + firstUpper(keyName) + "=?");
            con = getCon();
            pst = con.prepareStatement(sql.toString());
            setObject(pst, 1, key);
            int count = pst.executeUpdate();
            return count;
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } finally {
            close(con, pst);
        }
        return 0;
    }

    /**
     * 方 法 名:setObject
     * 功能描述:私有方法,设置preparedStatement的setXXX项
     * 输入参数: pst:PreparedStatement对象,i:列的位置,obj:要插入的对象
     * 返 回 值: void
     * 编 码 人:  zmj
     * 编码时间:  2010-2-8 上午11:13:02
     */
    private void setObject(PreparedStatement pst, int i, Object obj)
            throws SQLException {
        if (obj == null) {
            pst.setString(i, null);
        } else if (obj.getClass() == java.util.Date.class) {
            long l = ((java.util.Date) obj).getTime();
            java.sql.Timestamp t = new java.sql.Timestamp(l);
            pst.setTimestamp(i, t);
        } else {
            pst.setObject(i, obj);
        }
    }

    // 私有方法,把javabean存放到Object二维数组中
    private Object[][] bean2Array(Object bean) {
        Class<? extends Object> beanClass = bean.getClass();
        Field[] field = beanClass.getDeclaredFields();
        Method[] method = beanClass.getDeclaredMethods();
        ArrayList<Object> list = new ArrayList<Object>();
        for (int i = 0; i < field.length; i++) {
            for (int j = 0; j < method.length; j++) {
                String methodName = method[j].getName();
                if (isGetMethod(methodName)
                        && methodName.contains(firstUpper(field[i].getName()))) {
                    Object o = null;
                    try {
                        o = method[j].invoke(bean);
                    } catch (IllegalArgumentException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                    if (o != null) {
                        list.add(field[i].getName());
                        list.add(o);
                    }
                }
            }
        }
        int m = list.size();
        if (m < 1 || m % 2 != 0) {
            return new Object[0][0];
        }
        Object[][] bean_obj = new Object[m / 2][2];
        Iterator<Object> iter = list.iterator();
        int i = 0;
        while (iter.hasNext()) {
            bean_obj[i][0] = iter.next();
            bean_obj[i][1] = iter.next();
            i++;
        }
        return bean_obj;
    }

    // 私有方法,返回表中列名
    private String[] tableColName(ResultSet rs) throws SQLException {
        ResultSetMetaData rsmd = rs.getMetaData();
        int n = rsmd.getColumnCount();
        String[] name = new String[n];
        for (int i = 0; i < n; i++) {
            name[i] = rsmd.getColumnName(i + 1);
        }
        return name;
    }

    // 私有方法,保存ResultSet一行记录到一个javaBean中
    private void saveBean(Object bean, ResultSet rs, String[] paramName)
            throws SQLException {
        Method[] method = bean.getClass().getDeclaredMethods();
        for (int i = 0; i < paramName.length; i++) {
            for (int j = 0; j < method.length; j++) {
                String methodName = method[j].getName();
                if (methodName.endsWith(paramName[i])
                        && isSetMethod(methodName)) {
                    Object param = rs.getObject(paramName[i]);
                    if (param != null) {
                        // 如果为Timestamp类,则转换为Date类
                        if (param.getClass() == java.sql.Timestamp.class) {
                            long l = ((java.sql.Timestamp) param).getTime();
                            param = new java.util.Date(l);
                        }
                        try {
                            method[j].invoke(bean, param);
                        } catch (IllegalArgumentException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    // 私有方法,判断是否为getter方法
    private boolean isGetMethod(String methodName) {
        if (methodName == null)
            return false;
        return methodName.startsWith("is") || methodName.startsWith("get");
    }

    // 私有方法,判断是否为setter方法
    private boolean isSetMethod(String methodName) {
        if (methodName == null)
            return false;
        return methodName.startsWith("set");
    }

    // 私有方法,将首字母大写
    private String firstUpper(String s) {
        return s.substring(0, 1).toUpperCase() + s.substring(1);
    }

    // 私有方法,获取数据库连接
    private Connection getCon() throws ClassNotFoundException, SQLException {
        DB.getInstance();
        return DB.getConnection();
    }

    // 私有方法,关闭数据库操作1,用于查询数据库操作
    private void close(Connection con, PreparedStatement pst, ResultSet rs) {
        try {
            if (rs != null)
                rs.close();
            if (pst != null)
                pst.close();
            if (con != null)
                DB.release(con);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    // 私有方法,关闭数据库操作2,用于更新数据库操作
    //我用的数据库为access,不知道为什么,数据库Connection不关闭,数据库不更新,求解!!
    private void close(Connection con, PreparedStatement pst) {
        try {
            if (pst != null)
                pst.close();
            if (con != null) {
                con.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

 /*
 * 自己写的一个很简单的数据库连接池
 */

package com.drug.db;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Stack;

public class DB {
    private static DB DB_INSTANCE = null;
    private static int MAX = 40;
    private static Stack<Connection> CON_POOL = new Stack<Connection>();
    // 数据库配置
    private static String className = "sun.jdbc.odbc.JdbcOdbcDriver";
    private static String url = "jdbc:odbc:test";
    // 同步对象
    private final static byte[] lock = new byte[0];

    private DB() throws ClassNotFoundException {
        Class.forName(className);

    }

    // 返回单一实例
    public static DB getInstance() throws ClassNotFoundException {
        if (DB_INSTANCE == null) {
            DB_INSTANCE = new DB();
        }
        return DB_INSTANCE;
    }

    // 获取连接
    public static Connection getConnection() throws SQLException {
        synchronized (lock) {
            if (CON_POOL.isEmpty()) {
                return DriverManager.getConnection(url);
            }
            return CON_POOL.pop();
        }
    }

    // 释放连接
    public static void release(Connection con) throws SQLException {
        synchronized (lock) {
            if (con == null || con.isClosed()) {
                return;
            } else if (CON_POOL.size() < MAX + 1) {
                CON_POOL.push(con);
            } else {
                con.close();
            }
        }
    }
}

 

分享到:
评论
1 楼 myclover 2010-03-20  
不错,很厉害啊!

相关推荐

    浅谈数据库设计技巧[pdf]

    面向对象的程序开发,要做的第一件事就是,先分析整个程序中需 处理的数据,从中提取出抽象模板,以这个抽象模板设计类,再在其中逐步添加处理其数据 的函数(即算法),最后,再给类中的数据成员和函数划分访问...

    【05-面向对象(下)】

    •内部类提供了更好的封装,内部类成员可以直接访问外部类的私有数据,因为内部类被当成其他外部类成员。 •匿名内部类适合用于创建那些仅需要一次使用的类。 非静态内部类 •定义内部类非常简单,只要...

    Redis/MongoDB 接口封装(C++)

    5. 开发 AbstractMongodbModule 类处理通用的 MongoDB 数据库表数据操作 数据库中不同的表都有自己的 AbstractMongodbModule 子类对应 6. 用 Perl 开发自动代码生成器,上层程序员对照数据库表结构写 .tmpl 配置...

    Visual C++ 数据库系统开发完全手册.part2

    17.5 数据库封装类说明 17.5.1 概述 17.5.2 设计步骤 17.5.3 程序相关代码 17.6 主窗体设计 17.6.1 菜单设计 17.6.2 设计背景画面 17.6.3 程序设计与编码 17.7 采购管理设计 17.7.1 概述 17.7.2 设计步骤 17.7.3 ...

    Visual C++ 数据库系统开发完全手册.part1

    17.5 数据库封装类说明 17.5.1 概述 17.5.2 设计步骤 17.5.3 程序相关代码 17.6 主窗体设计 17.6.1 菜单设计 17.6.2 设计背景画面 17.6.3 程序设计与编码 17.7 采购管理设计 17.7.1 概述 17.7.2 设计步骤 17.7.3 ...

    python教程学习路线学习教程

    PYTHON学习教程 第1章初识Python 1.1Python 介绍 1.2Python IDE 开发工具 ...6.4数据库操作的封装 第7章Python Web 7.1Python Web 介绍 7.2使用Flask 框架搭建Web 项目 7.3Flask 框架路由 7.4Flask 框架模板

    超级有影响力霸气的Java面试题大全文档

    面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。 4. 多态性:  多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化...

    JAVA上百实例源码以及开源项目源代码

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    玩转模板--自动代码生成工程

    只一句代码就可以将一个字符串写入一个文件,如果我们自己写的话,得这样 打开一个文件,判断是否存在,判断编码类型,写入方式是追加还是覆盖,接着创建流,写入流,关闭流等等没有十几,二十行代码根本搞不定,还不一定见...

    写给大家看的面向对象编程书(第3版).[美]Matt Weisfeld(带详细书签).pdf

    1.4.1 类是对象模板 9 1.4.2 属性 11 1.4.3 方法 11 1.4.4 消息 11 1.5 使用UML完成类图建模 12 1.6 封装和数据隐藏 12 1.6.1 接口 12 1.6.2 实现 13 1.6.3 接口/实现范型的一个实际例子 13 1.6.4 接口/...

    通用类Gen V3.0使用手册

    由于VBS的类不支持静态方法,所以四个基础类都声明了一个默认的对象,分别是:F、An、Sn、Con,使用时直接用这些对象即可。Finish函数则负责释放这些对象。 Interface.asp还用于控制代码页、插入公共样式表、显示...

    基于J2EE框架的个人博客系统项目毕业设计论文(源码和论文)

    这些都预示着我们进入了一个新的互联网阶段web 2.0,它是相对web 1.0的新的一类互联网应用的总称,是一次从核心内容到外部应用的革命[10]。这个阶段发展迅速,互联网应用趋于多样化,其中变化最大的是由web 1.0网站...

    现代C++编程:从基础到实战项目全覆盖.docx

    简介 本教程旨在为初学者和中级程序员提供一个全面的C++学习路径,内容...小型数据库系统项目:设计并实现一个简单的数据库系统,练习文件操作和数据管理技能。 通过本教程的学习,你不仅能够掌握C++编程的基本技能,还

    JAVA上百实例源码以及开源项目

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    java 面试题 总结

    面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。 4. 多态性: 多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化多...

    二十三种设计模式【PDF版】

    各司其职的类串成一串,好象击鼓传花,当然如果自己能完成,就不要推委给下一个. 设计模式之 Mediator(中介) Mediator 很象十字路口的红绿灯,每个车辆只需和红绿灯交互就可以. 设计模式之 State(状态) 状态是编程中...

    PHP开发实战1200例(第1卷).(清华出版.潘凯华.刘中华).part1

    实例128 获取数组中最后一个元素 158 实例129 去除数组中的重复元素 158 实例130 字符串与数组的转换 159 实例131 对数组元素进行随机排序 160 实例132 随机抽取数组中元素 161 实例133 二维数组的输出 162 实例134 ...

    PHP开发实战1200例(第1卷).(清华出版.潘凯华.刘中华).part2

    实例128 获取数组中最后一个元素 158 实例129 去除数组中的重复元素 158 实例130 字符串与数组的转换 159 实例131 对数组元素进行随机排序 160 实例132 随机抽取数组中元素 161 实例133 二维数组的输出 162 实例134 ...

    java开源包8

    WARTS是一个纯Java数据库工具,可以执行字符编码识别的数据同步。开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的...

    java开源包4

    WARTS是一个纯Java数据库工具,可以执行字符编码识别的数据同步。开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的...

Global site tag (gtag.js) - Google Analytics