zoukankan      html  css  js  c++  java
  • Java JDBC的基础知识(五)

    本文主要记录JDBC基础知识之后的部分内容。另外,我看到《Java核心基础2》中第四章是主要介绍数据库编程的。里面有一些说明和应用特别灵活,有些部分也太容易理解,建议大家看一下。这篇是依然是剩余部分的基础。

    一、事务

    事务是一组组合成逻辑工作单元的操作,虽然系统中可能会出错,但事务将控制和维护事务中每个操作的一致性和完整性。

    事务具有:

    1.原子性(atomicity):组成事务处理的语句形成了一个逻辑单元,不能只执行其中的一部分。

    2.一致性(consistency):在事务处理执行前后,数据库是一致的(数据库数据完整性约束)。

    3.隔离性(isolcation):一个事务处理对另一个事务处理的影响。

    4.持续性(durability):事务处理的效果能够被永久保存下来 。

    用一副图来说明一下:

    Connection.setAutoCommit(false);  //打开事务
    Connection.commit();  //揭交事务
    Connection.rollback();  //回滚事务

    当只想撤销部分操作的时候,可以使用 SavePoint

    SavePoint sp=conn.getSavePoint();
    conn.rollback(sp);
    conn.commit();

    代码应用示例:

    import java.sql.Connection;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.ArrayList;
    import java.util.List;
    
    class AdminInfo {
        public static void main(String[] args) {
            AdminInfo admin = new AdminInfo();
            admin.setId(122);
            admin.setAddress("杭州文一西路");
            admin.setPassword("123");
            admin.setUserName("周周");
    
            List<Integer> roleList = new ArrayList<Integer>();
            roleList.add(3);
            roleList.add(4);
            roleList.add(5);
    
            addAdmin(admin, roleList);
    
        }
    
        private void setId(int i) {
            // TODO Auto-generated method stub
    
        }
    
        private void setAddress(String string) {
            // TODO Auto-generated method stub
    
        }
    
        private void setPassword(String string) {
            // TODO Auto-generated method stub
    
        }
    
        private void setUserName(String string) {
            // TODO Auto-generated method stub
    
        }
    
        private String getPassword() {
            // TODO Auto-generated method stub
            return null;
        }
    
        private String getUserName() {
            // TODO Auto-generated method stub
            return null;
        }
    
        private String getId() {
            // TODO Auto-generated method stub
            return null;
        }
    
        public static void addAdmin(AdminInfo admin, List<Integer> roleList) {
            Connection conn = null;
            Statement stm = null;
    
            try {
                conn = DBUtil.getConn();
                stm = conn.createStatement();
    
                String sql = "insert into adminInfo (id,userName,password) values ( "
                        + admin.getId()
                        + ",'"
                        + admin.getUserName()
                        + "','"
                        + admin.getPassword() + "') ";
    
                conn.setAutoCommit(false); // 开启事务
                stm.execute(sql);
    
                for (Integer i : roleList) {
                    String sql2 = "insert into adminRole(adminid,roleId) values ( "
                            + admin.getId() + "," + i + ")";
                    @SuppressWarnings("unused")
                    int a = 9 / 0;
                    stm.execute(sql2);
                }
    
                conn.commit();
    
            } catch (Exception ex) {
                try {
                    conn.rollback(); // 回滚
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                ex.printStackTrace();
            } finally {
                DBUtil.close(null, stm, conn);
            }
    
        }
    
    }

    二、带回滚点的事务

     从上面的图中,已经可以了解到,带滚点的事务的特点。只要设置了它,程序因为意外原因而中断,也可以当作数据都回到原来的起始点,就当什么事情都没发生过。

    代码操作演示:

    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    import java.sql.Savepoint;
    import java.util.List;
    
    public class Test4 {
        static void addUserPointDemo(String userName, String userId,
                List<Integer> roleList) {
            Connection conn = null;
            PreparedStatement stm = null;
            Savepoint point = null;
            try {
                conn = DBUtil.getConn();
                String sql = "insert into SysUser (userName,userId) values(?,?)";
                stm = conn.prepareStatement(sql);
                stm.setString(1, userName);
                stm.setString(2, userId);
    
                conn.setAutoCommit(false);
                stm.executeUpdate();
    
                // 下面是添加权限列表
                for (int i = 0; i < roleList.size(); i++) {
                    if (i == 3) { // 在等于3的时候设置保存点
                        point = conn.setSavepoint();
                    }
                    if (i == 5) {
                        int a = 2 / 0;
                    }
                    String sql2 = "insert into UserRole(userId,roleId) values(?,?)";
                    stm = conn.prepareStatement(sql2);
                    stm.setString(1, userId);
                    stm.setInt(2, roleList.get(i));
                    stm.executeUpdate();
                }
                conn.commit();
    
            } catch (Exception e) { // 注意这里的异常类型
                try {
                    conn.rollback(point);
                    conn.commit(); // 注意 一定要再commit 一次
                    throw new RuntimeException(e);
                } catch (SQLException e1) {
                    throw new RuntimeException(e1.getMessage());
                }
    
            }
        }
    }

    三、4 元信息

    DatabaseMetaData

    ParameterMetaData

    ResultSetMetaData

    1) DatabaseMetaData

    getURL():返回一个String类对象,代表数据库的URL。  //jdbc:mysql://localhost:3306/shop
    
    getUserName():返回连接当前数据库管理系统的用户名。 //root@localhost
    
    getDatabaseProductName():返回数据库的产品名称。  //MySQL
    
    getDatabaseProductVersion():返回数据库的版本号。
    
    getDriverName():返回驱动驱动程序的名称。 //MySQL-AB JDBC Driver
    
    getDriverVersion():返回驱动程序的版本号。 //mysql-connector-java-5.0.4 ( $Date: 2006-10-19 17:47:48 +0200 (Thu, 19 Oct 2006) $, $Revision: 5908 $ )
    
    isReadOnly():返回一个boolean值,指示数据库是否只允许读操作。//false
    
    supportsTransactions()  //true
    
    getSQLKeywords()  //AUTO_INCREMENT,BINARY,BLOB,ENUM,INFILE,LOAD,MEDIUMINT,OPTION,OUTFILE,REPLACE,SET,TEXT,UNSIGNED,ZEROFILL

    2) ParameterMetaData(stm.getParameterMetaData();)

    getParameterCount(): 获得指定参数的个数
    
    getParameterType(int param):获得指定参数的sql类型  //mysql不支持

    代码演示:

    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    
    public class Test5 {
        public static AdminInfo login(String sql, Object[] paramList) {
            Connection conn = null;
            PreparedStatement stm = null;
            ResultSet rs = null;
            AdminInfo admin = null;
    
            try {
                conn = DBUtil.getConn();
                stm = conn.prepareStatement(sql);
    
                /*
                 * ParameterMetaData pm=stm.getParameterMetaData(); int
                 * paramCount=pm.getParameterCount();
                 * System.out.println("该sql一共要"+paramCount+"个参数");
                 */
    
                for (int i = 1; i <= paramList.length; i++) {
                    stm.setObject(i, paramList[i - 1]);
                }
    
                rs = stm.executeQuery();
                if (rs.next()) {
                    admin = new AdminInfo();
                    admin.setId(rs.getInt("id"));
                    admin.setUserName(rs.getString("userName"));
                    admin.setPassword(rs.getString("password"));
                    // ...
                }
    
            } catch (Exception ex) {
                ex.printStackTrace();
            } finally {
                DBUtil.close(null, stm, conn);
            }
            return admin;
        }
    }

    3) ResultSetMeta (resultSet 的元信息)

    getColumnCount()  //得到列数
    
    getColumnName(int colum)  //得到指定列的列名 真名
    
    getColumnLabel(int colum) //得到指定列的列名 as 后的
    
    getColumnTypeName (int column) //得到指定列的类型

    代码演示:

    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    
    public class Test6 {
        public static AdminInfo test() {
            Connection conn = null;
            PreparedStatement stm = null;
            ResultSet rs = null;
            AdminInfo admin = null;
    
            try {
                conn = DBUtil.getConn();
                stm = conn
                        .prepareStatement("SELECT * FROM ADMININFO where username ='赵明明' and password='123'");
    
                rs = stm.executeQuery();
                if (rs.next()) {
                    ResultSetMetaData rm = rs.getMetaData();
                    int columnCount = rm.getColumnCount(); // 取列数
                    for (int i = 1; i <= columnCount; i++) {
                        System.out.println(rm.getColumnLabel(i)); // 取出所有的列名
                    }
    
                    admin = new AdminInfo();
                    admin.setId(rs.getInt("id"));
                    admin.setUserName(rs.getString("userName"));
                    admin.setPassword(rs.getString("password"));
                }
    
            } catch (Exception ex) {
                ex.printStackTrace();
            } finally {
                DBUtil.close(null, stm, conn);
            }
            return admin;
        }
    }

    四、数据源和连接池

    DataSource 用来取代 DriverManager 来取得Connection 。通过 DataSource 取得连接的速度很快。通过 DataSource 方式取得的连接(Connection ) 是经过代理的,它的close方法,不会导致原来的连接的关闭。一般的 DataSource 内部都有一个连接池来缓存 Connection,可以大大提高效率。这个连接池一般就是 一个 Collection 集合。

    例子:简单的数据源模拟

    //数据源
            public class MyDataSource {
                private String url="jdbc:mysql://localhost:3306/shop";
                private String user="root";
                private String password="admin";
                
                private LinkedList<Connection> connPool=new LinkedList<Connection>();
                
                public MyDataSource(){
                    for(int i=0;i<10;i++){
                        this.connPool.addLast(this.createConn());    
                    }
                }
            
                //对外提供取得连接的方法
                public Connection getConn(){
                    return this.connPool.removeFirst();
                }
                
                //对外提供收回连接的方法
                public  void closeConn(Connection conn){
                     this.connPool.addLast(conn);
                }
                
                //创建连接
                private Connection createConn() {
                    Connection conn=null;
                    try {
                        conn= DriverManager.getConnection(url,user,password);
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                    
                    return conn;
                }
            
            }
     //在DBUtil中使用自定义的数据源
       public class DBUtil {
                private DBUtil() {}
            
                private static MyDataSource myDataSorce=null; //数据源对象
                private static String className="com.mysql.jdbc.Driver";
            
                static {
                    try {
                        Class.forName(className);
                        myDataSorce=new     MyDataSource();    
                    } catch (ClassNotFoundException e) {
                        throw new RuntimeException(e);
                    }
                }
            
                // 得到连接
                public static Connection getConn() {
                    return myDataSorce.getConn();
                }
            
                // 关闭连接
                public static void close(ResultSet rs, Statement stm, Connection conn) {
                    if (rs != null) {
                        try {
                            rs.close();
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    }
                    if (stm != null) {
                        try {
                            stm.close();
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    }
                    if (conn != null) {
                        myDataSorce.closeConn(conn);     //关连接的方式也换掉了
                    }
            
                }
      }

    数据源产品的使用

    dbcp DataSource

    1) 导入jar 包

    commons-collections-3.1.jar

    commons-dbcp-1.2.2.jar

    commons-pool.jar

    配置文件

    dbcpconfig.properties

    2) 修改配置文件

    #连接设置

    driverClassName=com.mysql.jdbc.Driver

    url=jdbc:mysql://localhost:3306/shop

    username=root

    password=admin

    #<!-- 初始化连接 -->

    initialSize=10

    #最大连接数量

    maxActive=50

    #<!-- 最大空闲连接 -->

    maxIdle=20

    #<!-- 最小空闲连接 -->

    minIdle=5

    #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->

    maxWait=60000

    #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]

    #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。

    #connectionProperties=useUnicode=true;characterEncoding=gbk

    #指定由连接池所创建的连接的自动提交(auto-commit)状态。

    #defaultAutoCommit=true

    #driver default 指定由连接池所创建的连接的只读(read-only)状态。

    #如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)

    defaultReadOnly=

    #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。

    #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE

    defaultTransactionIsolation=READ_UNCOMMITTED

    import java.io.InputStream;
                import java.sql.Connection;
                import java.sql.ResultSet;
                import java.sql.SQLException;
                import java.sql.Statement;
                import java.util.Properties;
                import javax.sql.DataSource;
                import org.apache.commons.dbcp.BasicDataSourceFactory;
                
                public class DBUtil {
                    private DBUtil() {}
                    private static DataSource dataSource = null; // 数据源对象
                    
                    static {    
                        try {
                            // 读dbcp的配置文件
                            Properties settings = new Properties();
                            InputStream in = DBUtil.class.getClassLoader().getResourceAsStream(    "dbcpconfig.properties");
                            settings.load(in);
                            dataSource=BasicDataSourceFactory.createDataSource(settings);
                
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }
                
                    // 得到连接
                    public static Connection getConn() {
                        Connection conn= null;
                        try {
                            conn= dataSource.getConnection(); //返回的是一个代理对象
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                        return conn;
                    }
                
                    // 关闭连接
                    public static void close(ResultSet rs, Statement stm, Connection conn) {
                        if (rs != null) {
                            try {
                                rs.close();
                            } catch (SQLException e) {
                                e.printStackTrace();
                            }
                        }
                        if (stm != null) {
                            try {
                                stm.close();
                            } catch (SQLException e) {
                                e.printStackTrace();
                            }
                        }
                        if (conn != null) {
                            try {
                                conn.close();  //由于 conn 现在是个代理对象,所以它的close方法并不会真正的关掉连接,而是把它放回边接池中
                            } catch (SQLException e) {
                                e.printStackTrace();
                            }
                        }
                
                    }
                
                }
  • 相关阅读:
    mysql之优化器、执行计划、简单优化
    一条查询sql的执行流程和底层原理
    mysql建立索引,实际工作中建立索引的示例
    explain命令---查看mysql执行计划
    mysql 一些知识点
    开发中一些快捷键的使用
    simple-rpc
    maven
    数组合并排序
    SpringMVC配制全局的日期格式
  • 原文地址:https://www.cnblogs.com/1693977889zz/p/7273251.html
Copyright © 2011-2022 走看看