学习笔记-jdbc

JDBC

jdbc用来java与数据库连接,需要一些包(数据库驱动和一些连接池和工具包)
jar包分享地址
链接:https://pan.baidu.com/s/1lEBeZ-KUkcxhb7kk1sRecQ
提取码:1111

使用JDBC
//为了解耦合需要将连接数据库的配置写到properties文件中
public void getConnection(){
	InputStream in=null;
	Connection connection =null;
	try{
	//这里的Test类可以随意换成当前类
	in=Test.class.getClassLoader.getResourceAsStream("jdbc.properties");
	Properties properties=new Properties();
    properties.load(in);
    //获取properties中的配置信息
    String user = properties.getProperty("user");//数据库用户名
    String password = properties.getProperty("password");//数据库用户密码
    String url = properties.getProperty("url");//连接数据库url
    String driverClass = properties.getProperty("driverClass");//驱动包Driver
    //加载驱动
   	Class c=Class.forName(driverClass);
   	//获取数据库连接不需要在注册驱动,在获取driverClass时内部自动注册
    connection = DriverManager.getConnection(url, user, password);
	}catch (Exception e){
            e.printStackTrace();
        }finally{
            try {
                connection.close();
                in.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
    }
}
jdbc.properties中的内容
//jdbc.properties内容
user=root
password=123
url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true
driverClass=com.mysql.jdbc.Driver

这里连接mysql数据库,mysql是关系型数据库,将获取查询结果保存到对应的实体类(javabean)

javabean示例

ORM编程思想 (object relational mapping)
一个数据表对应一个java类
表中的一条记录对应java类的一个对象
表中的一个字段对应java类的一个属性

public class Customer {
    //类中的属性一一对应数据库表的列数据类型
	private int id;
    private String name;
    private String email;
    private Date birth;

    public Customer() {
    }

    public Customer(int id, String name, String email, Date birth) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.birth = birth;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", birth=" + birth +
                '}';
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }
}

对数据操作

基本上对数据库操作必须的步骤
第一步:获取数据库连接 Connection
第二部:获取执行sql语句的类对象 Statement或者PrepareStatement(sql语句可能会出现sql注入的问题,所以建议使用PrepareStatement,想了解Statement可自行搜索)
第三步:通过PrepareStatement进行调用,如果是查询操作会返回一个ResultSet对象,通过此对象可以获取数据库表数据
第四步:关闭数据库连接等一系列资源操作

jdbc工具类

在对数据库操作之前我们把固定的步骤给封装起来,岂不是方便很多,不用再每次都进行相同的操作

public class JDBCUtils {
//封装的获取connection连接的方法
	public static Connection getConnection() throws Exception{
        //直接通过ClassLoader类获取
        InputStream resourceAsStream = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
        Properties properties=new Properties();
        properties.load(resourceAsStream);
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driverClass = properties.getProperty("driverClass");
        //通过driver内部自动注册驱动
        Class.forName(driverClass);
        //获取连接
        Connection connection = DriverManager.getConnection(url, user, password);
        return connection;
    }
    //封装的关闭连接数据库的方法
    public static void closeResource(Connection conn, PreparedStatement ps, ResultSet rs){
    //每一处关闭操作都需要非空判断,有可能没有用到某个资源就调用了此方法
        try {
            if (conn!=null)
                conn.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        try {
            if (ps!=null)
                ps.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        try {
            if (rs!=null)
                rs.close();
        } catch (SQLException sqlException) {
            sqlException.printStackTrace();
        }
    }
}

工具类此时就封装好了,接下来写第一个sql操作插入数据
需要结合orm思想的javabean来操作

插入数据
 public void insert(Customer customer){
        Connection conn = null;
        PreparedStatement ps=null;
        try {
            //获取数据库连接
            conn=JDBCUtils.getConnection();
            //使用预编译的sql语句防止注入问题,id位主键自增,使用默认DEFAULT
            ps = conn.prepareStatement("insert into customers(id,name,email,birth) values(DEFAULT,?,?,?)");
            //设置每个列需要插入的数据,占位符?是从索引1开始
            ps.setString(1,customer.getName());
            ps.setString(2,customer.getEmail());
            ps.setDate(3,customer.getBirth());
           	int execute = ps.executeUpdate();
            System.out.println(execute);
            if (execute==1){
                System.out.println("插入数据成功");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.closeResource(conn,ps,null);
        }
    }

删除修改都是类似的操作,只是sql语句不同

查询操作
public void query() {
        Connection connection =null;
        PreparedStatement ps =null;
        ResultSet resultSet =null;
        List list=new ArrayList();//查询数据可能不止一条,按实际情况
        try {
            connection = JDBCUtils.getConnection();
            String sql="select id,name,email,birth from customers where id=?";
            ps = connection.prepareStatement(sql);
            ps.setInt(1,1);
            //执行并返回结果集
            resultSet = ps.executeQuery();
            //处理结果集
            //判断结果集下一行是否有数据,有数据返回true,指针下移,如果没有数据,返回false,指针不移动
            if (resultSet.next()){
                int id = resultSet.getInt(1);
                String name = resultSet.getString(2);
                String email = resultSet.getString(3);
                Date date = resultSet.getDate(4);
                Customer customer=new Customer(id,name,email,date);
                list.add(customer);
                System.out.println(customer);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            JDBCUtils.closeResource(connection,ps,resultSet);
        }
    }

操作基本是大同小异的,查询是有返回结果集的ResultSet
此时已经将查询方法写出来,但是我们需要查询特定的数据每次都需要修改?占位符的数据和sql语句,这样每次调用都需要重新进行重复操作,那太麻烦了,我们来将查询封装起来,需要传入什么数据就直接传入值进行查询

//封装查询方法
//使用可变参数,参数需要的指定数据
//返回值是你查询的类型
public Customer queryCustomer (String sql,Object ...args){
		Connection connection =null;
        PreparedStatement ps =null;
        ResultSet resultSet =null;
        Customer customer=null;//返回的对象类
        try {
            connection = JDBCUtils.getConnection();
            ps = connection.prepareStatement(sql);
            //将每个可变参数数据传入PreparedStatement ,注意与占位符?的顺序
            for (int i=0;i<args.length;i++){
                ps.setObject(i+1,args[i]);//这里需要+1,因为索引不是0开始
            }
        	//执行并返回结果集
            resultSet = ps.executeQuery();
            //处理结果集数据使用元数据和反射来进行操作,如果表数据太多,
            //需要将数据一个一个插入到实体类,那么太过麻烦
           	ResultSetMetaData metaData= resultSet.getMetaData();
           	//通过ResultSetMetaData获取结果集的列数
            int columnCount = metaData.getColumnCount();
            //处理结果集
            if (resultSet.next()){
            	customer=new Customer();
                for (int i=0;i<columnCount;i++){
                    Object object = resultSet.getObject(i + 1);//+1,索引从1开始
                    //获取每个列的列名
                    String columnName = metaData.getColumnName(i + 1);//如果列起了别名,获取别名的方法metaData.getColumnLabel();
                    //给customer指定的某个属性赋值/通过反射获取
                    Field declaredField = Customer.class.getDeclaredField(columnName);
                    declaredField.setAccessible(true);
                    declaredField.set(customer,object);
                }
                return customer;
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            JDBCUtils.closeResource(connection,ps,resultSet);
        }
        return customer;
}

//测试方法
	@Test
    public void testQuery(){
        String sql="select id,name,email,birth from customers where id=?";
        Customer customer = queryCustomer(sql, 1);
        System.out.println(customer);
    }
通用查询方法

上面将查询方法给封装了,不过,还是不够方便,因为只是针对一个表,接下来将是对所有表的查询方法的封装

所有表的查询操作封装


	//泛型方法,可以接受任何数据类型对象
    //需要通过反射将数据表中的数据映射到对应的实体类,所以需要传入需要操作对象的Class对象,并且设置为泛型,规范传入的数据
    public <T> T query(Class<T> c,String sql,Object ...args){
        Connection connection =null;
        PreparedStatement ps =null;
        ResultSet rs =null;
        T t=null;//接收结果集的对象
        try {
            connection = JDBCUtils.getConnection();
            ps = connection.prepareStatement(sql);
            for (int i=0;i<args.length;i++){
                ps.setObject(i+1,args[i]);
            }
            rs= ps.executeQuery();
            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();
            if (rs.next()){
                //获取需要返回类型的类对象,通过构造方法
                t= (T) c.newInstance();
                for (int i=0;i<columnCount;i++){
                    //获取列数据
                    Object object = rs.getObject(i + 1);
                    //获取列名
                    String columnName = metaData.getColumnName(i + 1);
                    //通过反射获取指定类的属性,为此类对象属性赋值
                    Field declaredField = c.getDeclaredField(columnName);
                    declaredField.setAccessible(true);
                    declaredField.set(t,object);
                }
                return t;
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            JDBCUtils.closeResource(connection,ps,rs);
        }
        return t;
    }

为什么使用泛型,因为此方法的封装是可以对所有javabean进行操作,所以返回类型并不能确定,所以使用泛型来代替将要操作的类型,参数的Class对象是来进行对需要的数据进行从数据库取值在赋值到对应的类中,而且需要传入泛型的Class对象,因为需要确定返回的类型是哪种类型,如果返回的是泛型,是不可以的(详细内容可以搜索泛型的规则,和泛型进行强转的规则)
这里返回特定的数据,如果需要返回所有查询结果,可以写成返回值为List<>使用泛型更安全,此处就不再写了

DAO包

在项目中创建一个DAO包专门用来进行数据库操作的实现类和接口
上面只是将方法进行了整体的封装,这次需要将方法封装到一个类中
使下次对方法的调用和外部对方法的调用更简单并且可以解耦合

//BaseDAO
//用来封装所有的基础操作,如查询修改等基本操作
public class BaseDAO<T> {
	//优化操作,对于指定的表查询操作动态的创建此表对应的java对应类的运行时对象
    //泛型Class,传入的泛型是什么类型就必须查询对应关系类型的数据表
    private Class<T> c=null;
	//静态代码块,继承此类的子类一创建对象就指定好对应的javabean对象的动态创建,不需要在每次方法参数中传入要创建的对象
	{
		//为什么用this,因为此处是子类调用的父类构造器,所以this代表子类对象
		Type genericSuperclass = this.getClass().getGenericSuperclass();
		ParameterizedType parameterizedType=(ParameterizedType) genericSuperclass;
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();//获取了父类的泛型参数
        c=(Class<T>) actualTypeArguments[0];//泛型第一个参数
	}
	//此时不再是泛型方法,而是通过泛型类确定返回值的泛型
	public List<T> getForList(Connection conn, String sql, Object ...args){
        PreparedStatement ps =null;
        ResultSet resultSet =null;
        try {
            ps = conn.prepareStatement(sql);
            for (int i=0;i<args.length;i++){
                ps.setObject(i+1,args[i]);
            }
            //执行并返回结果集
            resultSet = ps.executeQuery();
            //获取结果集的元数据
            ResultSetMetaData metaData = resultSet.getMetaData();
            //通过ResultSetMetaData获取结果集的列数
            int columnCount = metaData.getColumnCount();
            ArrayList<T> ts = new ArrayList<>();

            //处理结果集
            while (resultSet.next()){//判断结果集下一行是否有数据,有数据返回true,指针下移,如果没有数据,返回false,指针不移动
                T t=c.newInstance();
                for (int i=0;i<columnCount;i++){
                    Object object = resultSet.getObject(i + 1);
                    //获取每个列的列名
                    //获取每个列的别名
                    String columnName = metaData.getColumnLabel(i + 1);
                    //给customer指定的某个属性赋值/通过反射获取
                    Field declaredField = c.getDeclaredField(columnName);
                    declaredField.setAccessible(true);
                    declaredField.set(t,object);
                }
                ts.add(t);
            }
            return ts;
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            JDBCUtils.closeResource(null,ps,resultSet);
        }
        return null;
    }
}

//CustomerDAO   接口
//此接口用于规范针对customers表的常用操作
public interface CustomerDAO {
    //将customer对象添加到数据库中
    void insert(Connection conn, Customer customer);
    //将指定的id删除表中数据
    void deleteById(Connection conn,int id);
    //针对内存中的customer对象,去修改表中指定的记录
    void update(Connection conn,Customer customer);
    //针对指定的id查询得到对应的customer对象
    Customer getCustomerById(Connection conn,int id);
    //查询表中所有记录的集合
    List<Customer> getAll(Connection conn);
    //返回数据表中的数据条目数
    Long getCount(Connection conn);
    //返回数据表中最大的日期
    Date maxDate(Connection conn);
}
//CustomerDAOImpl  接口实现类
//DAO: data access object 数据访问对象
public class CustomerDAOImpl extends BaseDAO<Customer> implements CustomerDAO {
	@Override
    public List<Customer> getAll(Connection conn) {
        String sql="select name,email from customers";
        List<Customer> forList = getForList(conn, sql);//调用父类方法,因为继承父类指定了泛型,所以会返回指定泛型类型,防止接收其他类型返回值
        return forList;
    }
}

BaseDAO使用泛型,规范一个数据访问只能访问指定的类型数据,把类对象写入静态代码块,通过继承就可以动态的创建指定类,不需要在手动创建并传入。好处就是将业务代码进行了封装,需要什么业务就直接调用,不在需要调用类中写大量逻辑,方便以后的修改和迭代。

返回自增主键

有时候业务需要将新增的数据返回其主键,方法有很多,比如再做一次sql查询,使用官方api更简单

public int update(Connection conn,String sql,Object ...args){
        PreparedStatement ps=null;
        try {
        //使用两个参数的PreparedStatement 方法,第二个参数为Statement全局常量
            ps=conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
            for(int i=0;i<args.length;i++){
                ps.setObject(i+1,args[i]);
            }
            int i = ps.executeUpdate();
            //获取刚刚插入数据的自增主键
            ResultSet generatedKeys = ps.getGeneratedKeys();
            int anInt=0;
            if (generatedKeys.next()){
                anInt = generatedKeys.getInt(1);
            }
            return anInt;
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            JDBCUtils.closeResource(conn,ps);
        }
        return 0;
    }
批量插入数据
public void test() throws Exception{
        Connection connection= JDBCUtils.getConnection();
        String sql="insert into test(name) values(?)";
        PreparedStatement ps = connection.prepareStatement(sql);
        //设置自动提交为false,等最后一起提交
        connection.setAutoCommit(false);
        for (int i=0;i<=10000;i++){
            ps.setString(1,"name"+i);
            //要使用批量插入需要在连接数据库的url地址中加入一个属性
            //rewriteBatchedStatements=true
            //将sql语句添加到Batch
            ps.addBatch();
            //此处的判断根据实际情况
            if (i%500==0){
                //执行batch
                ps.executeBatch();
                //清空batch,清除之前已经执行的sql
                ps.clearBatch();
            }
        }
        //最后统一提交
        connection.commit();
        JDBCUtils.closeResource(connection,ps);
    }

大量数据插入时,使用批量插入可以减少很多时间

数据库插入图片等二进制文件
public class BlobTest {
    //向数据表插入blob字段
    @Test
    public void test() throws Exception {
        Connection connection= JDBCUtils.getConnection();
        String sql="insert into customers(name,email,birth,photo) values(?,?,?,?)";
        PreparedStatement ps = connection.prepareStatement(sql);
        ps.setObject(1,"坤坤");
        ps.setObject(2,"zhang@qq.com");
        ps.setObject(3,"1992-09-08");
        //路径是存放文件的路径
        File file=new File("tupian.jpg");
        InputStream inputStream=new FileInputStream(file);

        ps.setBlob(4,inputStream);
        ps.execute();
        JDBCUtils.closeResource(connection,ps);
    }
    //查询customers中的blob字段
    @Test
    public void testBlob() throws Exception{
        Connection connection= JDBCUtils.getConnection();
        String sql="select photo from customers where id=?";
        PreparedStatement ps = connection.prepareStatement(sql);
        ps.setInt(1,20);

        ResultSet resultSet = ps.executeQuery();
        if (resultSet.next()) {
            //blob字段下载下来以文件方式保存本地
            Blob blob = resultSet.getBlob(1);
            InputStream binaryStream = blob.getBinaryStream();
            FileOutputStream fileOutputStream=new FileOutputStream("maomi.jpg");
            byte[] bytes=new byte[1024];
            int len;
            while ((len=binaryStream.read(bytes))!=-1){
                fileOutputStream.write(bytes,0,len);
            }
            if (binaryStream!=null){
                binaryStream.close();
            }
            if (fileOutputStream!=null){
                fileOutputStream.close();
            }
        }

        JDBCUtils.closeResource(connection,ps,resultSet);
    }
}

并不建议将二进制文件传入数据库,这样会耗费大量时间,可以将图片保存到服务器,数据库存储保存路径,通过保存路径获取需要的图片资源

sql事务

事务的ACID属性

  • 原子性(Atomicity):原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生要么都不发生
  • 一致性(Consistency):事务必须使数据库从一个一致性状态变换到另外一个一致性状态
  • 隔离性(Isolation):事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事物之间不能相互干扰
  • 持久性(Durability):持久性是指一个事务一旦被提交,他对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响

connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);//设置数据库隔离级别
READ_UNCOMMITTED
READ_COMMITTED
REPEATABLE_READ
SERIALIZABLE(串列化)

public void test() {
        Connection connection=null;
        try {
            connection= JDBCUtils.getConnection();
            //自动提交为false
            connection.setAutoCommit(false);
            String sql="update user_table set balance=balance-100 where user=?";
            updateTest(connection,sql,"AA");
            //System.out.println(10/0);
            String sql2="update user_table set balance=balance+100 where user=?";
            updateTest(connection,sql2,"BB");
            //如果没有错误提交数据
            connection.commit();
        }catch (Exception e){
            try {
            //报错之后进行事务的回滚,必须回滚,虽然设置自动提交为false但是数据库连接关闭时还是会提交
                connection.rollback();
            } catch (SQLException sqlException) {
                sqlException.printStackTrace();
            }
            e.printStackTrace();
        }
        finally {
            try {
                //修改其为自动提交数据,主要针对于使用数据库连接池使用
                //设置连接为false之后需要将自动提交设置回来,因为如果是连接池的话连接是重复使用的
                connection.setAutoCommit(true);
            } catch (SQLException sqlException) {
                sqlException.printStackTrace();
            }
            JDBCUtils.closeResource(connection,null);
        }
    }

1.什么叫数据库事务
事务:一组逻辑操作单元,使数据从一种状态变换到另一种状态
一组逻辑操作单元:一个或多个dml操作

2.事务处理原则:保证所有事物都作为一个工作单元来执行,即使出现故障都不能改变这种执行方式。 当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),那么这些修改就永久的保存下来 , 要么数据库管理系统将放弃所有的修改,整个事务回滚(rollback)到最初状态

3.数据一旦提交不可回滚
>DML默认情况下操作一旦执行,都会自动提交
setAutoCommit=false的方式取消DML自动提交
>默认在关闭连接时,会自动提交数据

数据库连接池技术

数据库连接池(Database Connection Pooling)在程序初始化时创建一定数量的数据库连接对象并将其保存在一块内存区中,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个;释放空闲时间超过最大空闲时间的数据库连接以避免因为没有释放数据库连接而引起的数据库连接遗漏。
即在程序初始化的时候创建一定数量的数据库连接,用完可以放回去,下一个在接着用,通过配置连接池的参数来控制连接池中的初始连接数、最小连接、最大连接、最大空闲时间这些参数保证访问数据库的数量在一定可控制的范围类,防止系统崩溃,使用户的体验好。

c3p0

c3p0需要配置xml文件

<!--c3p0-config.xml-->
<?xml version="1.0" encoding="UTF-8" ?>
<c3p0-config>
    <named-config name="hellc3p0">
        <!--提供获取连接的4个基本属性 -->
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://<!--可省略localhost:3306-->/test?characterEncoding=utf8</property>
        <property name="user">root</property>
        <property name="password">123</property>
        <!--进行数据库连接池管理基本信息-->
        <!--当数据库连接池中的连接数不够时,c3p0一次性向服务器申请的连接数-->
        <property name="acquireIncrement">5</property>
        <!--初始化时连接数-->
        <property name="initialPoolSize">10</property>
        <!--最少连接数-->
        <property name="minPoolSize">10</property>
        <!--最大连接数-->
        <property name="maxPoolSize">100</property>
        <!-- intergalactoApp adopts a different approach to configuring statement caching -->
        <!--c3p0维护的最多的statement的个数-->
        <property name="maxStatements">50</property>
        <!--每个连接中可以最多使用的statement个数-->
        <property name="maxStatementsPerConnection">2</property>
    </named-config>
</c3p0-config>
public class C3P0 {
 //数据库连接池只提供一个即可
    private static ComboPooledDataSource cpds=new ComboPooledDataSource("hellc3p0");
    @Test
    public void c3p0Test() throws PropertyVetoException, SQLException {
        ComboPooledDataSource cpds = new ComboPooledDataSource();
        //配置可以在xml文件中配置,也可以在java代码中配置
        cpds.setDriverClass( "com.mysql.jdbc.Driver" ); //loads the jdbc driver
        cpds.setJdbcUrl( "jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=UTC" );
        cpds.setUser("root");
        cpds.setPassword("zhanghao123");
        //通过设置相关的参数,对数据库连接池进行管理
        //设置初始时数据库连接池中的连接数
        cpds.setInitialPoolSize(10);
		//获取连接池中的连接
        Connection conn=cpds.getConnection();
        System.out.println(conn);
        //销毁数据库连接池
     	//DataSources.destroy(cpds);
   	}
}

dbcp

dbcp配置properties文件,此处就不再写,其他配置可自行查阅

//dbcp.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?characterEncoding=utf8
username=root
password=123
//初始化连接个数
initialSize=10
public class Dbcp {
    //dbcp数据库连接池技术
	//使用配置文件连接数据库
    private static DataSource dataSource;
	static {
        Properties pros=new Properties();
        InputStream dbcpIn = ClassLoader.getSystemClassLoader().getResourceAsStream("dbcp.properties");
        try {
            pros.load(dbcpIn);
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            dataSource = BasicDataSourceFactory.createDataSource(pros);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void getDBCPConnection() throws SQLException {
        //任何一个连接池都有DataSource的实现类
        //创建了dbcp的数据库连接池
        BasicDataSource source=new BasicDataSource();
        //设置基本信息
        source.setDriverClassName("com.mysql.jdbc.Driver");
        source.setUrl("jdbc:mysql:///test?characterEncoding=utf8");
        source.setUsername("root");
        source.setPassword("zhanghao123");
        //还可以设置其他涉及数据库连接池管理的相关属性
        source.setInitialSize(10);
        source.setMaxActive(10);

        Connection connection = source.getConnection();
        System.out.println(connection);
    }
}

druid

druid配置properties文件

url=jdbc:mysql://localhost:3306/test?characterEncoding=utf8
username=root
password=123
driverClassName=com.mysql.jdbc.Driver

initialSize=10
maxActive=10
public class DruidTest {
    private static DataSource dataSource;
    static {
        Properties pros=new Properties();
        try {
            FileInputStream fileInputStream=new FileInputStream(new File("src/druid.properties"));
            pros.load(fileInputStream);
            dataSource = DruidDataSourceFactory.createDataSource(pros);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Test
    public void test() throws Exception {
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
    }
}
jdbc工具apach

apach提供的api就是封装好的与数据库交互的一些工具类,就像上面写好的一些封装方法

来看看怎么使用

public class QueryRunnerTest {
    @Test
    public void testInsert() throws Exception {
        QueryRunner runner=new QueryRunner();
        Connection connection = JDBCUtils.getConnection();
        String sql="insert into customers(name,email,birth) values(?,?,?)";
        int insertCount = runner.update(connection, sql, "蔡徐坤", "caixukun@126.com", "1997-01-09");
        System.out.println(insertCount);
        JDBCUtils.closeResource(connection,null);
    }
    //queryRunner查询
    //BeanHandler:是ResultSetHandler接口的实现类,用于封装表中的一条记录
    @Test
    public void testQ() throws Exception {
        QueryRunner runner=new QueryRunner();
        Connection connection = JDBCUtils.getConnection();
        String sql="select id,name,email,birth from customers where id=?";
        BeanHandler<Customer> handler=new BeanHandler<Customer>(Customer.class);

        Customer query = runner.query(connection, sql, handler, 21);
        System.out.println(query);
        JDBCUtils.closeResource(connection,null);

    }
    //BeanListHandler:是ResultSetHandler接口的实现类,用于封装表中的多条记录
    @Test
    public void testQ2() throws Exception {
        QueryRunner runner=new QueryRunner();
        Connection connection = JDBCUtils.getConnection();
        String sql="select id,name,email,birth from customers where id<?";
        BeanListHandler<Customer> handler=new BeanListHandler<Customer>(Customer.class);

        List<Customer> query = runner.query(connection, sql, handler, 21);
        System.out.println(query);
        JDBCUtils.closeResource(connection,null);

    }
    //ScalarHandler:是ResultSetHandler接口的实现类,用于查询特殊值
    @Test
    public void testScalar() throws Exception {
        QueryRunner runner=new QueryRunner();
        Connection connection = JDBCUtils.getConnection();
        String sql="select count(*) from customers";
        ScalarHandler handler=new ScalarHandler();

        Object query = runner.query(connection, sql, handler);
        System.out.println(query);
        dbClose(connection,null,null);
        //JDBCUtils.closeResource(connection,null);
    }
    //使用dbutils.jar中提供的DbUtils工具类,实现资源关闭
    public void dbClose(Connection conn, Statement ps, ResultSet rs) {
        try {
            DbUtils.close(conn);
        } catch (SQLException sqlException) {
            sqlException.printStackTrace();
        }
        try {
            DbUtils.close(rs);
        } catch (SQLException sqlException) {
            sqlException.printStackTrace();
        }
        try {
            DbUtils.close(ps);
        } catch (SQLException sqlException) {
            sqlException.printStackTrace();
        }
    }
}

其中获取连接还是需要自己的工具类获取连接,因为你的数据库只有你知道是什么名字和密码

初学者,可能有些地方的总结或者代码有错误,谅解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值