Java之JDBC学习

JDBC 简介

JDBC(Java Data Base Connectivity,java 数据库连接)是一种用于执行 SQL 语句的 JavaAPI,
可以为多种关系 数据库提供统一访问,它由一组用 Java 语言编写的类和接口组成。
JDBC 提供了一种基准,据此可以构建更高 级的工具和接口,使数据库开发人员能够编写数据库应用程序。

JDBC 原理

JDBC 是以前 SUN 公司定义的一套访问数据库的接口(没有具体实现),一套标准,具体的实现是由 各大数据库厂家去实现,每个数据库厂家都有自己的 JDBC 实现,也就是 JDBC 驱动实现类,Java 应用程序连接 指定数据库,需要使用厂家提供的 JDBC 驱动才能连接。(这里其实就是 java 多态的一种体现,一个接口可以有 很多具体的实现)

MySQL 8.0 以上版本的数据库连接有所不同

1、MySQL 8.0 以上版本驱动包版本 mysql-connector-java-8.0.16.jar。
2、com.mysql.jdbc.Driver 更换为 com.mysql.cj.jdbc.Driver。
MySQL 8.0 以上版本不需要建立 SSL 连接的,需要显示关闭。
什么是SSL?
SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层与应用层之间对网络连接进行加密。

最后还需要设置 CST。
CST是什么?
CST可视为美国、澳大利亚、古巴或中国的标准时间。

加载驱动与连接数据库方式如下:
Class.forName(“com.mysql.cj.jdbc.Driver”);
conn = DriverManager.getConnection(“jdbc:mysql://localhost:3306/test_demo?useSSL=false&serverTimezone=UTC”,“root”,“password”);
使用JDBC
思路
驱动的下载
https://mvnrepository.com/artifact/mysql/mysql-connector-java
导入jar包

在maven中配置

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.19</version>
</dependency>

加载驱动(装载相应的JDBC驱动并进行初始化)
获取与数据库的连接(建立JDBC和数据库之间的Connection连接)
获取向数据库发送SQL语句的statement(创建statement 或 preparedstatement接口,来执行SQL语句)
用statement向数据库发送SQL,并返回结果集resultset(处理和显示结果)
关闭连接释放资源(释放资源)

版本细节

// MySQL 8.0 以下版本 - JDBC 驱动名及数据库 URL
static final String JDBC_DRIVER = “com.mysql.jdbc.Driver”;
static final String DB_URL = “jdbc:mysql://localhost:3306/RUNOOB”;
// MySQL 8.0 以上版本 - JDBC 驱动名及数据库 URL
static final String JDBC_DRIVER = “com.mysql.cj.jdbc.Driver”;
/static final String DB_URL = “jdbc:mysql://localhost:3306/RUNOOB?useSSL=false&serverTimezone=UTC”;

UTC是什么?

UTC是协调世界时,又称世界统一时间、世界标准时间、国际协调时间。

详解各个类对象

1.DriverManager:驱动管理对象
  1. 注册驱动:告诉程序该使用哪一个数据库驱动jar
    static void registerDriver(Driver driver) :注册与给定的驱动程序 DriverManager 。
    写代码使用: Class.forName(“com.mysql.jdbc.Driver”);
    通过查看源码发现:在com.mysql.jdbc.Driver类中存在静态代码块
    static {
    try {
    java.sql.DriverManager.registerDriver(new Driver());
    } catch (SQLException E) {
    throw new RuntimeException(“Can’t register driver!”);
    }
    }

注意:mysql5之后的驱动jar包可以省略注册驱动的步骤。

2. Connection:数据库连接对象
			1. 获取执行sql 的对象
				 * Statement createStatement()
				 * PreparedStatement prepareStatement(String sql)  
			2. 管理事务:
				  * 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
				 * 提交事务:commit() 
				* 回滚事务:rollback() 
3. Statement:执行sql的对象
			执行sql
				 1. boolean execute(String sql) :可以执行任意的sql 了解 
				 2. int executeUpdate(String sql) :执行DML(insert、update、delete)语句、DDL(create,alter、drop)语句
				* 返回值:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功 返回值>0的则执行成功,反之,则失败。
				 3. ResultSet executeQuery(String sql)  :执行DQL(select)语句
4. ResultSet:结果集对象,封装查询结果
			 * boolean next(): 游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果是,则返回false,如果不是则返回true
			 * getXxx(参数):获取数据
				* Xxx:代表数据类型   如: int getInt() ,    String getString()
				* 参数:
					1. int:代表列的编号,从1开始   如: getString(1)
					 2. String:代表列名称。 如: getDouble("balance")
			* 注意:
				 * 使用步骤:
					 1. 游标向下移动一行
					 2. 判断是否有数据
					3. 获取数据
			* 练习:
				            * 定义一个方法,查询emp表的数据将其封装为对象,然后装载集合,返回。
				                1. 定义Emp类
				                2. 定义方法 public List<Emp> findAll(){}
				                3. 实现方法 select * from emp;
5. PreparedStatement:执行sql的对象
1. SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
				1. 输入用户随便,输入密码:a' or 'a' = 'a
				2. sql:select * from user where username = 'fhdsjkf' and password = 'a' or 'a' = 'a' 
			 2. 解决sql注入问题:使用PreparedStatement对象来解决
			3. 预编译的SQL:参数使用?作为占位符
			        4. 步骤:
				            1. 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
				            3. 获取数据库连接对象 Connection
				            2. 注册驱动
				            4. 定义sql
				5. 获取执行sql语句的对象 PreparedStatement  Connection.prepareStatement(String sql) 
				* 注意:sql的参数使用?作为占位符。 如:select * from user where username = ? and password = ?;
				6. 给?赋值:
					                * 方法: setXxx(参数1,参数2)
					                    * 参数1:?的位置编号 从1 开始
					                    * 参数2:?的值
				7. 执行sql,接受返回结果,不需要传递sql语句
				8. 处理结果
				 9. 释放资源
			        5. 注意:后期都会使用PreparedStatement来完成增删改查的所有操作
				            1. 可以防止SQL注入
				            2. 效率更高

代码

// MySQL 8.0 以下版本 - JDBC 驱动名及数据库 URL
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";  
static final String DB_URL = "jdbc:mysql://localhost:3306/RUNOOB";
// MySQL 8.0 以上版本 - JDBC 驱动名及数据库 URL
//static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver";  
//static final String DB_URL = "jdbc:mysql://localhost:3306/RUNOOB?useSSL=false&serverTimezone=UTC";
  static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";  
   static final String DB_URL = "jdbc:mysql://localhost:3306/RUNOOB";
   // 数据库的用户名与密码,需要根据自己的设置
   static final String USER = "root";
   static final String PASS = "123456";

   public static void main(String[] args) {
       Connection conn = null;
       Statement stmt = null;
       try{
           // 注册 JDBC 驱动
           Class.forName(JDBC_DRIVER);
       
           // 打开链接
           System.out.println("连接数据库...");
           conn = DriverManager.getConnection(DB_URL,USER,PASS);
       
           // 执行查询
           System.out.println(" 实例化Statement对象...");
           stmt = conn.createStatement();
           String sql;
           sql = "SELECT id, name, url FROM websites";
           ResultSet rs = stmt.executeQuery(sql);
       
           // 展开结果集数据库
           while(rs.next()){
               // 通过字段检索
               int id  = rs.getInt("id");
               String name = rs.getString("name");
               String url = rs.getString("url");
   
               // 输出数据
               System.out.print("ID: " + id);
               System.out.print(", 站点名称: " + name);
               System.out.print(", 站点 URL: " + url);
               System.out.print("\n");
           }
           // 完成后关闭
           rs.close();
           stmt.close();
           conn.close();
       }catch(SQLException se){
           // 处理 JDBC 错误
           se.printStackTrace();
       }catch(Exception e){
           // 处理 Class.forName 错误
           e.printStackTrace();
       }finally{
           // 关闭资源
           try{
               if(stmt!=null) stmt.close();
           }catch(SQLException se2){
           }// 什么都不做
           try{
               if(conn!=null) conn.close();
           }catch(SQLException se){
               se.printStackTrace();
           }
       }
       System.out.println("Goodbye!");
   }
}

数据库事务

事务的特性
1.原子性(Atomicity):原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 
2.一致性(Consistency):在一个事务中,事务前后数据的完整性必须保持一致,可以想象银行转账、火车购票。
3.隔离性(Isolation):多个事务,事务的隔离性是指多个用户并发访问数据库时, 一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。
4.持久性(Durability):持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

数据库连接池

连接池的定义

数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库连接池正是针对这个问题提出来的。
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。

连接池编写案例

代码

public class JdbcPool implements DataSource{  
   
    /** 
    * @Field: Connections 
    *         使用Vector来存放数据库链接, 
    *         Vector具备线程安全性 
    */  
    private static Vector Connections = new Vector();  
      
    static{  
        //在静态代码块中加载db.properties数据库配置文件  
        InputStream in = JdbcPool.class.getClassLoader().getResourceAsStream("db.properties");  
        Properties prop = new Properties();  
        try {  
            prop.load(in);  
            String driver = prop.getProperty("driver");  
            String url = prop.getProperty("url");  
            String username = prop.getProperty("username");  
            String password = prop.getProperty("password");  
            //数据库连接池的初始化连接数大小  
            int jdbcPoolInitSize =Integer.parseInt(prop.getProperty("jdbcPoolInitSize"));  
            //加载数据库驱动  
            Class.forName(driver);  
            for (int i = 0; i < jdbcPoolInitSize; i++) {  
                Connection conn = DriverManager.getConnection(url, username, password);  
                System.out.println("获取到了链接" + conn);  
                //将获取到的数据库连接加入到Connections集合中,Connections此时就是一个存放了数据库连接的连接池  
                Connections.addElement(conn);  
            }  
              
        } catch (SQLException e) {  
            System.out.println(" 创建数据库连接失败! " + e.getMessage());  
            throw new SQLException();  
        }  
    }  
      
    @Override  
    public PrintWriter getLogWriter() throws SQLException {  
        // TODO Auto-generated method stub  
        return null;  
    }  
   
    @Override  
    public void setLogWriter(PrintWriter out) throws SQLException {  
        // TODO Auto-generated method stub  
          
    }  
   
    @Override  
    public void setLoginTimeout(int seconds) throws SQLException {  
        // TODO Auto-generated method stub  
          
    }  
   
    @Override  
    public int getLoginTimeout() throws SQLException {  
        // TODO Auto-generated method stub  
        return 0;  
    }  
   
    @Override  
    public <T> T unwrap(Class<T> iface) throws SQLException {  
        // TODO Auto-generated method stub  
        return null;  
    }  
   
    @Override  
    public boolean isWrapperFor(Class<?> iface) throws SQLException {  
        // TODO Auto-generated method stub  
        return false;  
    }  
   
    /* 获取数据库连接 
     * @see javax.sql.DataSource#getConnection() 
     */  
    @Override  
    public Connection getConnection() throws SQLException {  
        //如果数据库连接池中的连接对象的个数大于0  
        if (Connections.size()>0) {  
            //从Connections集合中获取一个数据库连接  
            final Connection conn = Connections.removeFirst;  
            System.out.println("Connections数据库连接池大小是" + Connections.size());  
            //返回Connection对象的代理对象  
            return (Connection) Proxy.newProxyInstance(JdbcPool.class.getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler(){  
                @Override  
                public Object invoke(Object proxy, Method method, Object[] args)  
                        throws Throwable {  
                    if(!method.getName().equals("close")){  
                        return method.invoke(conn, args);  
                    }else{  
                        //如果调用的是Connection对象的close方法,就把conn还给数据库连接池  
                        Connections.addElement(conn);  
                        System.out.println(conn + "被还给Connections数据库连接池了!!");  
                        System.out.println("Connections数据库连接池大小为" + Connections.size());  
                        return null;  
                    }  
                }  
            });  
        }else {  
            throw new RuntimeException("对不起,数据库忙");  
        }  
    }  
   
    @Override  
    public Connection getConnection(String username, String password)  
            throws SQLException {  
        return null;  
    }  
}  

配置信息

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcStudy
username=root
password=root
jdbcPoolInitSize=10

开源数据库连接池

		DBCP 数据库连接池
			DBCP 是 Apache 软件基金组织下的开源连接池实现,要使用DBCP数据源,需要应用程序应在系统中增加如下两个 jar 
			 1. Commons-dbcp.jar:连接池的实现
				http://commons.apache.org/proper/commons-dbcp/download_dbcp.cgi
			2. Commons-pool.jar:连接池实现的依赖库
				http://commons.apache.org/proper/commons-pool/download_pool.cgi
			使用
				1.导入相关jar包
					        commons-dbcp-1.2.2.jar、commons-pool.jar
				2、在类目录下加入dbcp的配置文件:dbcpconfig.properties
				dbcpconfig.properties的配置信息如下:

连接设置

 driverClassName=com.mysql.jdbc.Driver  
 url=jdbc:mysql://localhost:3306/jdbcstudy  
 username=root  
 password=root 
    
 #<!-- 初始化连接 -->  
 initialSize=10  
    
 #最大连接数量  
 maxActive=50  
    
 #<!-- 最大空闲连接 -->  
 maxIdle=20  
    
 #<!-- 最小空闲连接 -->  
 minIdle=5  
    
 #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->  
 maxWait=60000  
    
    
 #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]  
 #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。  
 connectionProperties=useUnicode=true;characterEncoding=UTF8  
    
 #指定由连接池所创建的连接的自动提交(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  

连接工具类

public class JdbcUtils_DBCP {  
    /** 
     * 在java中,编写数据库连接池需实现java.sql.DataSource接口,每一种数据库连接池都是DataSource接口的实现 
     * DBCP连接池就是java.sql.DataSource接口的一个具体实现 
     */  
    private static DataSource ds = null;  
    //在静态代码块中创建数据库连接池  
    static{  
        try{  
            //加载dbcpconfig.properties配置文件  
            InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");  
            Properties prop = new Properties();  
            prop.load(in);  
            //创建数据源  
            ds = BasicDataSourceFactory.createDataSource(prop);  
        }catch (Exception e) {  
            throw new ExceptionInInitializerError(e);  
        }  
    }  
      
    /** 
    * @Method: getConnection 
    * @Description: 从数据源中获取数据库连接 
    * @return Connection 
    * @throws SQLException 
    */  
    public static Connection getConnection() throws SQLException{  
        //从数据源中获取数据库连接  
        return ds.getConnection();  
    }  
      
    /** 
    * @Method: release 
    * @Description: 释放资源, 
    * 释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement对象,存储查询结果的ResultSet对象 
    * 
    * @param conn 
    * @param st 
    * @param rs 
    */  
    public static void release(Connection conn,Statement st,ResultSet rs){  
        if(rs!=null){  
            try{  
                //关闭存储查询结果的ResultSet对象  
                rs.close();  
            }catch (Exception e) {  
                e.printStackTrace();  
            }  
            rs = null;  
        }  
        if(st!=null){  
            try{  
                //关闭负责执行SQL命令的Statement对象  
                st.close();  
            }catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
          
        if(conn!=null){  
            try{  
                //将Connection连接对象还给数据库连接池  
                conn.close();  
            }catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
    }  
}  

C3P0 数据库连接池

C3P0数据源

C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。C3P0数据源在项目开发中使用得比较多。

c3p0与dbcp区别

  1. dbcp没有自动回收空闲连接的功能
  2. c3p0有自动回收空闲连接功能

使用

1.导入相关jar包
c3p0-0.9.2-pre1.jar、mchange-commons-0.2.jar,如果操作的是Oracle数据库,那么还需要导入c3p0-oracle-thin-extras-0.9.2-pre1.jar
2.在类目录下加入C3P0的配置文件:

c3p0-config.xml

c3p0-config.xml的配置信息如下:

 <?xml version="1.0" encoding="UTF-8"?>  
    <!--  
    c3p0-config.xml必须位于类路径下面  
    private static ComboPooledDataSource ds;  
    static{  
        try {  
            ds = new ComboPooledDataSource("MySQL");  
        } catch (Exception e) {  
            throw new ExceptionInInitializerError(e);  
        }  
    }  
    -->  
       
    <c3p0-config>  
        <!--  
        C3P0的缺省(默认)配置,  
        如果在代码中“ComboPooledDataSource ds = new ComboPooledDataSource();”这样写就表示使用的是C3P0的缺省(默认)配置信息来创建数据源  
        -->  
        <default-config>  
            <property name="driverClass">com.mysql.jdbc.Driver</property>  
            <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy</property>  
            <property name="user">root</property>  
            <property name="password">XDP</property>  
              
            <property name="acquireIncrement">5</property>  
            <property name="initialPoolSize">10</property>  
            <property name="minPoolSize">5</property>  
            <property name="maxPoolSize">20</property>  
        </default-config>  
       
        <!--  
        C3P0的命名配置,  
        如果在代码中“ComboPooledDataSource ds = new ComboPooledDataSource("MySQL");”这样写就表示使用的是name是MySQL的配置信息来创建数据源  
        -->  
        <named-config name="MySQL">  
            <property name="driverClass">com.mysql.jdbc.Driver</property>  
            <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy</property>  
            <property name="user">root</property>  
            <property name="password">XDP</property>  
              
            <property name="acquireIncrement">5</property>  
            <property name="initialPoolSize">10</property>  
            <property name="minPoolSize">5</property>  
            <property name="maxPoolSize">20</property>  
        </named-config>  
       
    </c3p0-config>

连接工具类

public class JdbcUtils_C3P0 {  
      
    private static ComboPooledDataSource ds = null;  
    //在静态代码块中创建数据库连接池  
    static{  
        try{  
            //通过代码创建C3P0数据库连接池  
            /*ds = new ComboPooledDataSource(); 
            ds.setDriverClass("com.mysql.jdbc.Driver"); 
            ds.setJdbcUrl("jdbc:mysql://localhost:3306/jdbcstudy"); 
            ds.setUser("root"); 
            ds.setPassword("XDP"); 
            ds.setInitialPoolSize(10); 
            ds.setMinPoolSize(5); 
            ds.setMaxPoolSize(20);*/  
              
            //通过读取C3P0的xml配置文件创建数据源,C3P0的xml配置文件c3p0-config.xml必须放在src目录下  
            //ds = new ComboPooledDataSource();//使用C3P0的默认配置来创建数据源  
            ds = new ComboPooledDataSource("MySQL");//使用C3P0的命名配置来创建数据源  
              
        }catch (Exception e) {  
            throw new ExceptionInInitializerError(e);  
        }  
    }  
      
    /** 
    * @Method: getConnection 
    * @Description: 从数据源中获取数据库连接 
    * @return Connection 
    * @throws SQLException 
    */  
    public static Connection getConnection() throws SQLException{  
        //从数据源中获取数据库连接  
        return ds.getConnection();  
    }  
      
    /** 
    * @Method: release 
    * @Description: 释放资源, 
    * 释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement对象,存储查询结果的ResultSet对象 
    * 
    * @param conn 
    * @param st 
    * @param rs 
    */  
    public static void release(Connection conn,Statement st,ResultSet rs){  
        if(rs!=null){  
            try{  
                //关闭存储查询结果的ResultSet对象  
                rs.close();  
            }catch (Exception e) {  
                e.printStackTrace();  
            }  
            rs = null;  
        }  
        if(st!=null){  
            try{  
                //关闭负责执行SQL命令的Statement对象  
                st.close();  
            }catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
          
        if(conn!=null){  
            try{  
                //将Connection连接对象还给数据库连接池  
                conn.close();  
            }catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
    }  
}  

html字符实体

比如我们想在网页上面显示一个“<”小于符号,但是“<”在HTML中是文档标记的开始语言,如果我们直接使用“<”会出差错,所以我们就会一些实体名称来代替!

显示结果———-描述———-实体名称———-实体编号
 --------------------空格-------------&nbsp;---------&#160;
<--------------------小于号-----------&lt;-----------&#60;
>--------------------大于号-----------&gt;-----------&#62;
&--------------------和号------------&amp;-----------&#38;
"--------------------引号------------&quot; ---------&#34;
'--------------------撇号------------&apos;----------&#39;(IE不支持)
¢--------------------分-------------&cent;----------&#162;
£--------------------镑--------------&pound;---------&#163;
¥--------------------日圆------------&yen;-----------&#165;
€--------------------欧元------------&euro;----------&#8364;
§--------------------小节------------&sect;----------&#167;
©--------------------版权------------&copy;----------&#169;
®--------------------注册商标---------&reg;-----------&#174;
™--------------------商标------------&trade;----------&#8482;
×--------------------乘号------------&times;----------&#215;
÷--------------------除号------------&divide;---------&#247;

项目班级管理系统(作业)

对班级信息实现

add
delete
update
select
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值