【JDBC简介、JDBC程序编写步骤、JDBC工具类编写、数据库连接池、JDBC管理事务、commons-dbutils工具类库使用、JDBC批处理机制、单元测试】

JDBC简介、JDBC程序编写步骤、JDBC工具类编写、数据库连接池、JDBC管理事务、commons-dbutils工具类库使用、JDBC批处理机制、单元测试

一、JDBC(Java Database Connectivity)简介

1.JDBC:java连接数据库的规范(标准),可以使用java语言连接各种不同的关系型数据库,并完成CRUD操作

2.JDBC的本质

		JDBC的本质是一个java类,实现了sun公司规定的“数据库应用程序接口规范”,该类也称为jar包或数据库驱动,由不同的数据库厂商提供,通过该jar包或者数据库驱动,才能访问不同的关系型数据库,并对其数据进行CRUD操作

3.JDBC常用API

1)java.sql.Driver 驱动接口

			有一个Driver类实现了Driver接口
				普通方法:
				1>驱动对象.connect(String url,Properties properties);    返回连接对象
				2>静态代码块.    用于类加载时注册驱动	
public class Driver implements java.sql.Driver{
	static{
		try{
			java.sql.DriverManager.registerDriver(new Driver());
		}catch(SQLException E){
			throw new RuntimeException("Cant't register driver!");
		}
	}
}

2)java.sql.DriverManager 驱动管理类(管理jdbc驱动服务)

				静态方法:
				1>DriverManager.registerDriver(Driver driver);    用于注册驱动
				2>DriverManager.getConnection(String url,String username, String possword);       用于返回连接对象
					url:统一资源定位符-(由协议、IP、端口、库名组成)
						例.  jdbc:mysql://localhost:3306:数据库名
					username:数据库用户名
					possword:数据库登陆密码

3)java.sql.Connection 数据库连接接口

				普通方法
				1>连接对象名.createStatement();     返回Statement执行对象
				2>连接对象名.prepareStatement(String sql); 	返回PreparedStatement预编译对象,并将参数化的sql语法发送给数据库编译后,存储到预编译对象中
				参数化sql:字段的值没有给定,使用?(占位符或参数标记),后续通过预编译对象的set方法设定值
						例:insert into 表名 values(?,?...);
				3>连接对象名.setAutoCommit();   设定事务提交方式(false为手动提交)
				4>连接对象名.rollback();    回滚事物
				5>连接对象名.commit();   提交事物

4)java.sql.Statement 数据库静态sql执行接口

				普通方法
				1>执行对象名.executeUpdate(String sql);           返回int型的受影响的行数
						用于对数据库DML或者DDL(表)的操作
				2>执行对象名.executeQuery(String sql);        返回ResultSet查询结果集的对象
						用于对数据库DQL的操作
				3>执行对象名.execute(sql);       执行任意sql语句,返回boolean值
				静态sql语句:直接写定的sql语句
						例:insert into 表名 values(值1,值2...);

5)java.sql.PreparedStatement (继承了Statement接口) 数据库预编译执行接口

				普通方法
				1>预编译对象名.set字段类型(index,values);      给占位符第index位,设定values值
				2>预编译对象名.setObject(index,values);
				3>预编译对象名.executeUpdate();        返回int型的受影响的行数
						 用于对数据库DML或者DDL(表)的操作
				4>预编译对象名.executeQuery(String sql);        返回ResultSet查询结果集对象
						用于对数据库DQL的操作
				5>预编译对象名.execute(sql);      执行任意sql语句,返回boolean值
				6>预编译对象名.addBatch();  添加需要批处理的sql语句或参数
				7>预编译对象名.executeBatch();   执行批量处理语句
				8>预编译对象名.clearBatch();    清空批处理包的语句

6)java.sql.ResultSet 接收数据库查询结果集接口

				普通方法
				1>结果集对象名.next();        返回boolean值,用于判断是否有下一行记录,如有,光标下移一行,如没有,返回false
				2>结果集对象名.first();        用于将光标移动到第一行
				3>结果集对象名.previous();      返回boolean值,用于判断是否有上一行记录,如有,光标上移一行,如没有,返回false
				4>结果集对象名.get字段类型(index或者字段名);   用于获取指定索引或者字段的值,接收类型时字段类型对应的java类型
				5>结果集对象名.getObject(index或字段名);   用于获取指定索引或者字段的值,接收类型是Object

7)javax.sql.DataSource 数据源接口

			普通方法:
			1>数据源对象名.getConnection();    返回连接对象

8)com.alibaba.druid.pool.DruidDataSourceFactory 德鲁伊数据源工厂类

				com.alibaba.druid.pool.DruidDataSource实现了javax.sql.DataSource接口
			静态方法:
			1>DruidDDataSourceFactory.createDataSource(Properties properties);   返回数据源对象

9) org.apache.commons.dbutils.QueryRunner 查询执行类(里面封装了PreparedStatement,Connection以及释放资源的方法)

		普通方法:
		1>对象名.query(String sql,ResultSetHandler rsh , Object ...param);      依据rsh不同实现子类,返回对应类型结果
		2>对象名.query(Connection conn,String sql,ResultSetHandler rsh, Object ...param);可以加入事务(默认自动提交,通过该方法加入事务)
		3>对象名.Update(String sql , Object...param)
		4>对象名.Update(Connection conn,String sql,Object ...param);可以加入事务(默认自动提交,通过该方法加入事务)

10)ResultSetHandler接口的实现子类

		ArrayHandler
		ArrayListHandler
		BeanHandler:可以将查询到结果集中的记录封装到一个java实体类中
			实体类类名 对象名 =new BeanHandler<实体类名>(实体类的字节码文件);
		BeanListHandler:可以将查询的多条记录封装到list集合中
			List<实体类名> list = new BeanListHandler<实体类名>(实体类的字节码文件);
		BearnMapHandler:可以将查询的多条记录封装到Map中
		ScalarHandler:查询单行单列的数据(例聚合函数中查询总记录数)
			Object obj = new ScalarHandler<>();
			String s = String.valueOf(obj);
			int counts =Integer.parseInt(s);

二、JDBC程序编写步骤

1.使用DriverManger类或者Driver类获取连接对象方式(7大步骤)

		1)导包并注册驱动--加载Driver类
		2)获得客户端或java程序的数据库连接--得到Connection
		3)编写静态或者参数化sql语句
		4)获得执行对象或者预编译对象
		5)执行sql语句(DDL、DML、DQL)
		6)返回结果
		7)释放资源--先开后关

2.使用数据库池

	1)导包并配置好数据库连接池的配置文件		
	2)读取配置文件并获得数据源对象(数据库连接池对象)
	3)获取数据库的连接对象
	4) 编写sql语句
	5)获得执行对象或者预编译对象
	6)执行sql语句(DDL、DML、DQL)
	7)返回执行结果
	8)释放资源--先开后关

3.使用commons-dbutils(工具类库)

	1)导包
	2) 获取数据源对象
	3)获取QueryRunner对象并传入数据源对象
	4)准备sql语句
	5)执行sql语句
	6)返回结果

	(该工具类库中封装了PreparedStatement、Connection以及资源的释放)

三、使用DriverManger类或者Driver类

1.Driver

package com.hua.Test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.util.Properties;

public class TestDriver {
    public static void main(String[] args) throws Exception {
        //第一步:导包并注册驱动(以下两种方式都可以)
        Driver driver = new com.mysql.jdbc.Driver();
//        Class<?> cls = Class.forName("com.mysql.jdbc.Driver");
//        Driver driver1 =(Driver) cls.newInstance();

        Properties prop = new Properties();
        prop.load(new FileInputStream("src//driver.properties"));
        //第二步:获取连接对象
        Connection conn = driver.connect("jdbc:mysql://localhost:3306/myee_2202", prop);
        //第三步:准备静态sql
        String sql1 = "update emp01 set name = 'lin' where id = 1";  //静态sql
        // 第四步:获取执行对象
        Statement statement = conn.createStatement();//执行对象
        //第五步:执行sql语句并返回结果
        int i1 = statement.executeUpdate(sql1);
        System.out.println(i1==1 ? "成功":"失败" );


        //第三步:准备动态sql
        String sql2 = "update emp01 set name = ? where id =? ";//动态sql
        //第四步:获取预编译对象
        PreparedStatement ps = conn.prepareStatement(sql2);//预编译对象
        ps.setString(1,"scalar");
        ps.setInt(2,3);
        //第五步:执行sql并返回结果
        int i2 = ps.executeUpdate();
        System.out.println(i2==1 ? "成功":"失败" );

        //第六步:释放资源
        ps.close();
        statement.close();
        conn.close();
    }
}

2. DriverManager


package com.hua.Test;
import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;

public class TestDriver {
    public static void main(String[] args) throws Exception {
        //第一步:导包并注册驱动
        DriverManager.registerDriver(new com.mysql.jdbc.Driver());
        Properties prop = new Properties();
        prop.load(new FileInputStream("src//driver.properties"));
        //第二步:获取连接对象
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/myee_2202", prop);
        //第三步:准备静态sql
        String sql1 = "update emp01 set name = 'abby' where id = 1";  //静态sql
        // 第四步:获取执行对象
        Statement statement = conn.createStatement();//执行对象
        //第五步:执行sql语句并返回结果
        int i1 = statement.executeUpdate(sql1);
        System.out.println(i1==1 ? "成功":"失败" );


        //第三步:准备动态sql
        String sql2 = "update emp01 set name = ? where id =? ";//动态sql
        //第四步:获取预编译对象
        PreparedStatement ps = conn.prepareStatement(sql2);//预编译对象
        ps.setString(1,"demon");
        ps.setInt(2,3);
        //第五步:执行sql并返回结果
        int i2 = ps.executeUpdate();
        System.out.println(i2==1 ? "成功":"失败" );

        //第六步:释放资源
        ps.close();
        statement.close();
        conn.close();
    }
}

3.Statement 与 PreparedStatement的区别

	1>执行效率
		Statement 只能执行静态sql语句,每执行一条,都需要单独发给数据库编译,效率低
		PreparedStatement可以通过参数化sql语句,动态填充数据,同构造的sql语句只需在获取预编译对象时发送给数据库编译一次,编译后的sql会储存到预编译对象中,后续通过预编译对象的set方法设定不同的值,执行效率高
	2>sql注入
		Statement的sql语句是字符串拼接而成,而且是在用户输入数据,整合后发给数据库编译,如果用户输入的数据中包含关键字或者语法,会导致sql注入问题
		PreparedStatement的sql语句是在获取预编译对象时发送给数据库编译,在用户输入数据前已编译好完整的sql语句,此时即便用户输入SQL关键字或者语法也不会影响已编译的sql语句,有效避免了SQL注入

提示:
1.mysql驱动5.1.6及以后可以无需写Class.forName(“com.mysql.jdbc.Driver”);
2.从jdk1.5以后使用了jdbc4,就不需要显示的调用class.forName()注册驱动而是自动调用驱动jar包下的META-INF\services\java.sql.Driver文本中的类名称去注册

四、数据库连接池

1.简介

		1)Jdbc的数据库连接池使用javax.sql.DataSource表示,DataSourc只是一个接口,通常由第三方提供实现			
		2)预先在缓冲池中放入一定数量的连接对象,当需要连接数据库时,从缓冲池中取出一个连接对象,使用完后归还
		3)数据库连接池负责分配、管理、释放连接,它允许应用程序使用一个现有的连接,而不是重新建立一个
		4)当应用程序向连接池请求的连接数超过最大数量时,这些请求将被加入到等待队列

2.传统获取Connection的问题分析

		1)传统的JDBC数据库连接是通过DriverManger类的静态方法获取,每次向数据库建立连接,都要将Connection加载到内存中,再验证IP地址、用户名、密码(约耗时0.05~1s),如频繁的进行数据库连接操作会占用很多系统资源,容易造成服务器奔溃
		2)每一次数据库连接,使用完后都得断开,如果程序出现异常而未能关闭,将导致数据库内存泄漏 ,最终将导致重启数据库
		3)传统获取连接的方式,不能控制连接数量,如果连接过多,也会导致内存泄漏,Mysql崩溃

3.数据库连接池的种类

	1)C3P0数据库连接池:速度相对较慢,稳定性不错(hibernate,spring中有使用)
	2)DBCP数据库连接池:速度相对C3P0较快,但不稳定
	3)Proxool数据库连接池:有监控连接池状态的功能,稳定性较C3P0差一点
	4)BoneCP数据库连接池:速度快
	5)Druid(德鲁伊)数据库连接池:是阿里提供的,集C3P0、DBCP、Proxool优点于一身

传统方式连接数量较多,崩溃的代码演示

package com.hua.Test;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
public class SqlBreakdowm {
    public static void main(String[] args) {
        Properties  properties = new Properties();
        try {
            properties.load(new FileInputStream("src//Jdbc01.properties"));
            String url = properties.getProperty("url");
            String user = properties.getProperty("user");
            String password = properties.getProperty("password");
            for (int i = 0; i <= 5000; i++) {
                Connection conn = DriverManager.getConnection(url,user,password);
                System.out.println("连接第" + i + "次");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    } 
}
运行结果:
连接第1次~第103com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected establishment of connection,  message from server: "Too many connections"

4.C3P0数据库连接池的使用

步骤:

	1)导包
	2)获得数据源对象
	3)
第一种方式,在程序中设置参数
  //获取数据源对象
  ComboPooledDataSource cpds = new ComboPooledDataSource();
  //通过配置文件获取相关信息
  Properties prop = new Properties();
  prop.load(new FileInputStream("src//Jdbc.properties"));
  String url = prop.getProperty("url");
  String username = prop.getProperty("username");
  String password = prop.getProperty("password");
  String driverpath = prop.getProperty("driverpath");
  //给数据源设置相关的参数
  cpds.setDriverClass(driverpath);
  cpds.setJdbcUrl(url);
  cpds.setUser(username);
  cpds.setPassword(password);
  //初始化连接数
  cpds.setInitialPoolSize(10);
  //最大连接数
  cpds.maxPoolSize(50); 
  //获取连接对象
  Connection conn = cpds.getConnection();   
  
  
  
  
	第二种方式,使用C3P0提供的配置文件
//将C3P0提供的c3p0.config.xml拷贝到src目录下(该文件指定了连接数据库和连接池的相关参数)
//在c3p0.config.xml文件中设置参数
//获取数据源对象
ComboPooledDataSource cpds = new ComboPooledDataSource(“数据源名称”);
//获取连接对象
Connection conn = cpds.getConnection();   

5.Druid数据库连接池的使用

package com.hua.Test;


import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

public class DruidSqlPool {
    public static void main(String[] args) {
        // 第一步导包(druid-1.1.10.jar)并配置好数据库连接池中的文件
        /*
            注意:配置文件中的key按DruidDataSource中的参数写,不能随意自定义,不然读取不到
            driverClassName=com.mysql.jdbc.Driver
            url=jdbc:mysql://localhost:3306/myee_2202
            username=root
            password=123456
            initialSize=10      //初始化连接数量
            maxActive=10        //最大激活数量
            minIdle=4           //最小空闲数量
            maxwait=3000        //最大等待时间


         */
        //第二步:读取配置文件并获取数据源对象
        Properties prop = new Properties();
        ResultSet rs = null;
        PreparedStatement ps = null;
        Connection conn = null;
        try {
            prop.load(new FileInputStream("src//druid.properties"));
            DataSource ds = DruidDataSourceFactory.createDataSource(prop);
            //第三步:获取连接对象
            conn = ds.getConnection();
            //第四步:编写sql语句
            String sql = "select * from emp01 where id =  ?";
            //第五步:获取预编译对象,并将sql语句发送数据库编译
            ps = conn.prepareStatement(sql);
            ps.setInt(1,3);
            //第六步:执行sql
            rs = ps.executeQuery();
            //第七步:返回结果
            while (rs.next()) {
                int id = rs.getInt("id");
                String name = rs.getString("name");
                int age = rs.getInt("age");
                String gender = rs.getString("gender");
                String address = rs.getString("address");
                int salary = rs.getInt("salary");
                System.out.println(id + "\t" + name + "\t" + age + "\t" + gender + "\t" + address + "\t" + salary);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (rs == null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                 }

                if (ps == null) {
                    try {
                        ps.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                    }
                    if (conn == null) {
                        try {
                            conn.close();
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    }
                }
        }
    }
运行结果:

五月 21, 2022 3:46:10 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
3	fiona	25	female	poland	25000

五、JDBC 编写工具类(连接池)

1.步骤

	1)定义属性,并私有化构造函数
	2)静态代码块用于注册驱动、读取配置文件并初始化属性
	3)定义一个静态方法用于提供数据源对象
	4)定义一个静态方法用于提供连接对象
	5)定义方法用于释放资源


注意:由于每个线程都有自己的连接对象,需要先判断当前线程有没有连接对象,如有,直接获取,如没有再从连接池获取并绑定到当前线程,资源释放后,需要解绑连接对象!!

2.示例代码


package com.hua.Test;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

public class TestJdbcUtils {
    //第一步:定义属性,私有化构造函数
    private static ThreadLocal<Connection> tl = new  ThreadLocal<Connection>();
    private static DataSource ds;
    private TestJdbcUtils() {
    }

    //第二步:静态代码块用于读取配置文件,并创建数据源对象
    static{
        //读取配置文件(以下两种方式都可以获得输入流,任选一个)
        Properties prop = new Properties();
        try {
            prop.load(new FileInputStream("src//druid.properties"));
            //prop.load(TestJdbcUtils.class.getClass().getResourceAsStream("druid.properties"));
            //获取数据源对象
            ds = DruidDataSourceFactory.createDataSource(prop); 
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //第三步:定义一个静态方法用于提供数据源对象
    public static DataSource getDataSourceObject(){
        return  ds;
    }

    //第四步:定义一个静态方法用于提供连接对象
    public static Connection getConnectionObject() throws SQLException {
        //先判断当前线程中是带有连接
        Connection conn = tl.get();
        if (conn == null) {
            conn = ds.getConnection();
            //此次注意将连接对象绑定给当前线程
            tl.set(conn);
        }
        return conn;
    }

    //第五步:定义静态方法用于释放资源
    public static void  close(PreparedStatement ps, Connection conn){
        closeAll(null,ps,conn);
    }
    public static void closeAll(ResultSet rs, PreparedStatement ps, Connection conn){
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (ps != null) {
            try {
                ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
                //此处注意解绑当前线程的连接对象
                tl.remove();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    //使用main方法测试工具类是否可以正常使用
    public static void main(String[] args) {
        for (int i = 0; i <=200 ; i++) {
            try {
                Connection conn = TestJdbcUtils.getConnectionObject();
                System.out.println("连接了" + i + "次"+conn);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
运行结果:
五月 21, 2022 4:20:03 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
连接了0com.mysql.jdbc.JDBC4Connection@233c0b17
连接了1com.mysql.jdbc.JDBC4Connection@63d4e2ba
连接了2com.mysql.jdbc.JDBC4Connection@7bb11784
连接了3com.mysql.jdbc.JDBC4Connection@33a10788
连接了4com.mysql.jdbc.JDBC4Connection@7006c658
连接了5com.mysql.jdbc.JDBC4Connection@34033bd0
连接了6com.mysql.jdbc.JDBC4Connection@47fd17e3
连接了7com.mysql.jdbc.JDBC4Connection@7cdbc5d3
连接了8com.mysql.jdbc.JDBC4Connection@3aa9e816
连接了9com.mysql.jdbc.JDBC4Connection@17d99928

//解释:由于最大激活数量限定了10,所以只分配了10个连接对象


六、JDBC管理事务


package com.hua.Test;
import org.apache.commons.dbutils.QueryRunner;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

public class TestCommit {
    public static void main(String[] args) {
        DataSource ds = TestJdbcUtils.getDataSourceObject();
        Connection conn = null;
        try {
             conn = TestJdbcUtils.getConnectionObject();
             //设置为手动提交
            conn.setAutoCommit(false);
            QueryRunner qr = new QueryRunner(ds);
            String sql1 = "update account set balance = balance + 800 where id = 1 ";
            String sql2="update account set balance = balance - 800 where id = 2 ";
            qr.update(conn,sql1);
            //int i =10/0;
            qr.update(conn,sql2);
            //全部执行完毕时提交事务
            conn.commit();
        } catch (Exception e) {
            e.printStackTrace();
            try {
                //有异常时自动回滚
                conn.rollback();
                System.out.println("事务已回滚");
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }
    }
}

七、commons-dbutils工具类库以及使用

		1.dbutils是Apache组织机构旗下的开源工具类库
		2.针对原生jdbc进行了封装,简化了jdbc操作
		3.API参考以上(9,10)
package com.hua.Test;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.hua.pojo.Emp01;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.List;

public class TestCommonsDbutils {
    public static void main(String[] args) {
        //第一步:导包(commons-dbutils核心包与依赖包)
        //第二步:获取数据源对象(使用自己封装的工具类)
        DataSource ds = TestJdbcUtils.getDataSourceObject();
        //第二步:获取QueryRunner对象
        QueryRunner qr = new QueryRunner(ds);
        //编写sql语句
        String sql = "select * from emp01";
        //执行sql语句,并将记录存放到List集合中
        List<Emp01> list = null;
        try {
            list = qr.query(sql, new BeanListHandler<Emp01>(Emp01.class));
        } catch (SQLException e) {
            e.printStackTrace();
        }
        for (Emp01 emp01 : list) {
            System.out.println(emp01);
        }
    }
}
package com.hua.Test;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.hua.pojo.Emp01;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.List;

public class TestCommonsDbutils {
    public static void main(String[] args) {
        //第一步:导包(commons-dbutils核心包与依赖包)
        //第二步:获取数据源对象(使用自己封装的工具类)
        DataSource ds = TestJdbcUtils.getDataSourceObject();
        //第二步:获取QueryRunner对象
        QueryRunner qr = new QueryRunner(ds);
        //编写sql语句
        String sql = "select * from emp01 where id = ?";
        //执行sql语句,并将记录存放到实体类对象中

        Emp01 emp01 = null;
        try {
            emp01 = qr.query(sql, new BeanHandler<Emp01>(Emp01.class), 2);
            System.out.println(emp01 );
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
运行结果:
五月 21, 2022 5:08:44 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
Emp01{id=2, name='tom', age=21, gender='male', address='england', salary=15000}

八、JDBC批处理

1.当需要成批插入或者更新记录时,可以采用java的批量处理机制,往往和PreparedStatement搭配使用,既可以减少编译次数,有减少运行次数,效率大大提高

2.相关方法API请参考常用API中第五点

3.注意:使用批处理时,必须在url中加参数?rewriteBatchedStatements=true ,如果没有添加该参数,使用批处理方法无效

4.示例代码如下

1)单独处理批量数据


package com.hua.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;

public class TestNoBatch {
    public static void main(String[] args) throws Exception {
        Connection conn = TestJdbcUtils.getConnectionObject();
        String sql = "insert into account values(null, ?,?)";
        PreparedStatement ps = conn.prepareStatement(sql);
        long start = System.currentTimeMillis();

        for (int i = 1; i <=5000 ; i++) {
            ps.setString(1,"jack"+i);
            ps.setInt(2,(1000+i));
            ps.executeUpdate();
        }
        long end = System.currentTimeMillis();
        System.out.println("单独插入批量数据耗时" + (end - start));
    }
}
运行结果:
五月 22, 2022 10:49:57 上午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
单独插入批量数据耗时1907


2)使用批处理机制处理批量数据

package com.hua.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;

public class TestNoBatch {
    public static void main(String[] args) throws Exception {
        Connection conn = TestJdbcUtils.getConnectionObject();
        String sql = "insert into account values(null, ?,?)";
        PreparedStatement ps = conn.prepareStatement(sql);
        long start = System.currentTimeMillis();
        for (int i = 1; i <=5000 ; i++) {
            ps.setString(1,"jack"+i);
            ps.setInt(2,(1000+i));
            //增加批处理机制
            ps.addBatch();

            if((i % 1000) == 0){
                //执行批处理sql语句
                ps.executeBatch();
                //清空批处理包
                ps.clearBatch();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("使用批处理机制插入批量数据耗时" + (end - start));
    }
}
运行结果:
五月 22, 2022 10:57:46 上午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
使用批处理机制插入批量数据耗时219

九、单元测试

1.单元测试分类

	白盒测试:技术含量大于黑盒测试---测试开发方向
	黑盒测试

2.操作步骤

	1)导包(junit核心包以及hmrecrest-core依赖包)
	2)编写单元测试方法(注意改方法没有返回值类型,没有参数,不能在构造函数私有的类中使用)
	3)标记方法为单元测试,在方法上面加@Test注解
	4)在junit包下一个断言Assert,来判断测试功能的结果
	(如果测试自己的功能可以不用断言,可以直接接口多态测试数据是否存在)

九、常见错误

java.lang.ClassNotFoundException:找不到类

	类名写错、没有导入jar包

java.sql.SQLException:与sql语句相关的错误

	约束错误、表名、列名书写错误
	建议:在客户端工具中测试sql语句之后再粘贴

com.mysql.jdbc.exception.jdbc4.MySQLSyntaxErrorException:Unknow column

	列值String类型没有加单引号

Duplicate entry ‘1’ for key ‘PRIMARY’

主键值已存在或者混乱,更改主键值或者清空表

com.mysql.jdbc.exception.jdbc4.MySQLSyntaxErrorException:Unkonw column ‘password’ in

	原因:可能输入的值的类型不对

与poppy一起学习

	预习Servlet
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值