jdbc笔记2

Posted escapist

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jdbc笔记2相关的知识,希望对你有一定的参考价值。

private static String driver;
    private static String url;
    private static String username;
    private static String password;
    

    static{
        ResourceBundle bundle = ResourceBundle.getBundle("db");
        driver = bundle.getString("driver");
        url = bundle.getString("url");
        username = bundle.getString("username");
        password = bundle.getString("password");
    }
private static String driver;
    private static String url;
    private static String username;
    private static String password;

    static {
        try {
            // 1.通过当前类获取类加载器
            ClassLoader classLoader = JDBCUtils_V3.class.getClassLoader();
            // 2.通过类加载器的方法获得一个输入流
            InputStream is = classLoader.getResourceAsStream("db.properties");
            // 3.创建一个properties对象
            Properties props = new Properties();
            // 4.加载输入流
            props.load(is);
            // 5.获取相关参数的值
            driver = props.getProperty("driver");
            url = props.getProperty("url");
            username = props.getProperty("username");
            password = props.getProperty("password");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

 

主从表数据更新问题

当两张表没有建立任何关系的时候,那么可以随意删除其中任何一张表中的任何记录,但是一旦把两张表建立了关系(主外键约束)之后,那么不能删除主表

中的数据(这些数据内容在从表中有关联关系的数据),只想执行删除(更新操作)。

要想删除主表中与从表有关联关系的数据,可以这么做:

  1. 解除主从表的约束关系
  2. 先删除从表中与主表有关系的数据,再删除主表中的数据。

 

关于子查询问题

一般子查询会存在于两张关联的表中,那么我们可以先把带有条件的那张表与另外一张表的关联关系字段查出来,并作为另外一张表查询的条件值,然后再次进行查询。

select * from product where category_id=( select cid  from category where cname=’化妆品’);

 

关于mysql编码问题

查看MySQL编码       SHOW VARIABLES LIKE ‘char%‘;

l  character_set_client:你发送的数据必须与client指定的编码一致!!!服务器会使用该编码来解读客户端发送过来的数据;

l  character_set_connection:通过该编码与client一致!该编码不会导致乱码!当执行的是查询语句时,客户端发送过来的数据会先转换成connection指定的编码。但只要客户端发送过来的数据与client指定的编码一致,那么转换就不会出现问题;

l  character_set_database:数据库默认编码,在创建数据库时,如果没有指定编码,那么默认使用database编码;

l  character_set_server:MySQL服务器默认编码;

l  character_set_results:响应的编码,即查询结果返回给客户端的编码。这说明客户端必须使用result指定的编码来解码;

 

修改character_set_client、character_set_results、character_set_connection为GBK,就不会出现乱码了。但其实只需要修改character_set_client和character_set_results。

 

控制台的编码只能是GBK,而不能修改为UTF8,这就出现一个问题。客户端发送的数据是GBK,而character_set_client为UTF8,这就说明客户端数据到了服务器端后一定会出现乱码。既然不能修改控制台的编码,那么只能修改character_set_client为GBK了。

服务器发送给客户端的数据编码为character_set_result,它如果是UTF8,那么控制台使用GBK解码也一定会出现乱码。因为无法修改控制台编码,所以只能把character_set_result修改为GBK。

l  修改character_set_client变量:set character_set_client=gbk;

l  修改character_set_results变量:set character_set_results=gbk;

 

自定义连接池

* SUN公司提供了一个连接池的接口.(javax.sql.DataSource).

* 定义一个连接池:实现这个接口.

* 使用List集合存放多个连接的对象.

public class MyDataSource implements DataSource{
    // 创建一个List集合用于存放多个连接对象.
    private List<Connection> list = new ArrayList<Connection>();
    // 在程序开始的时候,初始化几个连接,将连接存放到list中.
    public MyDataSource() {
        // 初始化3个连接:
        for(int i=1;i<=3;i++){
            Connection conn = JDBCUtils.getConnection();
            list.add(conn);
        }
    }
    
    @Override
    // 获得连接的方法:
    public Connection getConnection() throws SQLException {
        if(list.size() <= 0){
            for(int i=1;i<=3;i++){
                Connection conn = JDBCUtils.getConnection();
                list.add(conn);
            }    
        }
        Connection conn = list.remove(0);
        return conn;
    }
    
    // 归还连接的方法:
    public void addBack(Connection conn){
        list.add(conn);
    }
...
}

自定义连接池中问题及如何解决

问题?

1.如果使用自定义连接池,那么需要额外记住自定义连接池中的API.

2.能不能使用面向接口的编程方式.

 

如何增强Connectionclose方法:  放到连接池中

增强一个Java类中的某个方法有几种方式

继承的方式  能够控制这个类的构造的时候,才可以使用继承


继承的方式增强一个类中某个方法:
class Man{
    public void run(){
        System.out.println("跑....");
    }
}
 
class SuperMan extends Man{
    public void run(){
        // super.run();
        System.out.println("飞....");
    }
}

装饰者模式方式.

包装对象和被包装的对象都要实现相同的接口.

包装的对象中需要获得到被包装对象的引用.

缺点:如果接口的方法比较多,增强其中的某个方法.其他的功能的方法需要原有调用.

使用装饰者的方式完成类的方法的增强
interface Waiter{
    public void server();
}
 
class Waiteress implements Waiter{
 
    @Override
    public void server() {
        System.out.println("服务...");
    }
}
class WaiteressWrapper implements Waiter{
    private Waiter waiter;
 
    public WaiteressWrapper(Waiter waiter) {
        this.waiter = waiter;
    }
    
    @Override
    public void server() {
        System.out.println("微笑...");
        // this.waiter.server();
    } 
}
public class MyConnection implements Connection{
    private Connection conn;
    private List<Connection> list;
 
    public MyConnection(Connection conn,List<Connection> list) {
        this.conn = conn;
        this.list = list;
    }
    @Override
    public void close() throws SQLException {
        list.add(conn);
    }
     ...
}
 
连接池的getConnection方法:
    @Override
    // 获得连接的方法:
    public Connection getConnection() throws SQLException {
        if(list.size() <= 0){
            for(int i=1;i<=3;i++){
                Connection conn = JDBCUtils.getConnection();
                list.add(conn);
            }    
        }
        Connection conn = list.remove(0);
        MyConnection myConn = new MyConnection(conn, list);
        return myConn;
    }

动态代理的方式.

被增强的对象实现接口就可以.

 

DBCP

DBCP(DataBase connection pool),数据库连接池。是 apache 上的一个 java 连接池项目,也是 tomcat 使用的连接池组件。

单独使用dbcp需要2个包:commons-dbcp.jar,commons-pool.jar由于建立数据库连接是一个非常耗时耗资源的行为,所以通常连

接池都是预先建立一些连接,放在内存中,应用程序需要建立数据库连接时直接到连接池中申请一个就行,用完后再放回去。

第一步:引入DBCP连接池的jar包.

第二步:编写DBCP代码:

    * 手动设置参数:

    * 配置文件设置参数

@Test
    public void demo1(){
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql:///web_07");
        dataSource.setUsername("root");
        dataSource.setPassword("123");
        try{
            // 获得连接:
            conn = dataSource.getConnection();
            // 编写SQL:
            String sql = "select * from category";
            // 预编译SQL:
            stmt = conn.prepareStatement(sql);
            // 执行SQL:
            rs = stmt.executeQuery();
            while(rs.next()){
                System.out.println(rs.getInt("cid")+"   "+rs.getString("cname"));
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JDBCUtils.release(rs,stmt, conn);
        }
    }
    
    @Test
    /**
     * 配置文件方式:
     */
    public void demo2(){
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        Properties properties = new Properties();
        
        try{
            properties.load(new FileInputStream("src/dbcpconfig.properties"));
            DataSource dataSource = BasicDataSourceFactory.createDataSource(properties);
            // 获得连接:
            conn = dataSource.getConnection();
            // 编写SQL:
            String sql = "select * from category";
            // 预编译SQL:
            stmt = conn.prepareStatement(sql);
            // 执行SQL:
            rs = stmt.executeQuery();
            while(rs.next()){
                System.out.println(rs.getInt("cid")+"   "+rs.getString("cname"));
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JDBCUtils.release(rs,stmt, conn);
        }
    }

 

C3P0

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

第一步:引入C3P0连接池的jar包.

第二步:编写代码:

* 手动设置参数:

* 配置文件设置参数:

public class JDBCUtils2 {
    private static final ComboPooledDataSource DATA_SOURCE =new ComboPooledDataSource();
    public static Connection getConnection(){
        Connection conn = null;
        try {
            conn = DATA_SOURCE.getConnection();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return conn;
    }

 

ResultSetHandler

我们知道在执行select语句之后得到的是ResultSet,然后我们还需要对ResultSet进行转换,得到最终我们想要的数据。你可以希望把ResultSet的数据放到一个List中,

也可能想把数据放到一个Map中,或是一个Bean中。

 

DBUtils提供了一个接口ResultSetHandler,它就是用来ResultSet转换成目标类型的工具。你可以自己去实现这个接口,把ResultSet转换成你想要的类型。

DBUtils提供了很多个ResultSetHandler接口的实现,这些实现已经基本够用了,我们通常不用自己去实现ResultSet接口了

 

l  MapHandler:单行处理器!把结果集转换成Map<String,Object>,其中列名为键!

l  MapListHandler:多行处理器!把结果集转换成List<Map<String,Object>>;

l  BeanHandler:单行处理器!把结果集转换成Bean,该处理器需要Class参数,即Bean的类型;

l  BeanListHandler:多行处理器!把结果集转换成List<Bean>;

l  ColumnListHandler:多行单列处理器!把结果集转换成List<Object>,使用ColumnListHandler时需要指定某一列的名称或编号,例如:new ColumListHandler(“name”)表示把name列的数据放到List中。

l  ScalarHandler:单行单列处理器!把结果集转换成Object。一般用于聚集查询,例如select count(*) from tab_student。

 

QueryRunner之查询

QueryRunner的查询方法是:

  public <T> T query(String sql, ResultSetHandler<T> rh, Object… params)

  public <T> T query(Connection con, String sql, ResultSetHandler<T> rh, Object… params)

query()方法会通过sql语句和params查询出ResultSet,然后通过rh把ResultSet转换成对应的类型再返回。

   public void fun1() throws SQLException {
        DataSource ds = JdbcUtils.getDataSource();
        QueryRunner qr = new QueryRunner(ds);
        String sql = "select * from tab_student where number=?";
        Map<String,Object> map = qr.query(sql, new MapHandler() , "S_2000");
        System.out.println(map);
    }
    public void fun2() throws SQLException {
        DataSource ds = JdbcUtils.getDataSource();
        QueryRunner qr = new QueryRunner(ds);
        String sql = "select * from tab_student";
        List<Map<String,Object>> list = qr.query(sql, new MapListHandler() );
        for(Map<String,Object> map : list) {
            System.out.println(map);
        }
    }
    public void fun3() throws SQLException {
        DataSource ds = JdbcUtils.getDataSource();
        QueryRunner qr = new QueryRunner(ds);
        String sql = "select * from tab_student where number=?";
        Student stu = qr.query(sql, new BeanHandler<Student>(Student.class) , "S_2000");
        System.out.println(stu);
    }
    public void fun4() throws SQLException {
        DataSource ds = JdbcUtils.getDataSource();
        QueryRunner qr = new QueryRunner(ds);
        String sql = "select * from tab_student";
        List<Student> list = qr.query(sql, new BeanListHandler<Student>(Student.class)); 
        for(Student stu : list) {
            System.out.println(stu);
        }
    }
    public void fun5() throws SQLException {
        DataSource ds = JdbcUtils.getDataSource();
        QueryRunner qr = new QueryRunner(ds);
        String sql = "select * from tab_student";
        List<Object> list = qr.query(sql, new ColumnListHandler("name") );
        for(Object s : list) {
            System.out.println(s);
        }
    }
    public void fun6() throws SQLException {
        DataSource ds = JdbcUtils.getDataSource();
        QueryRunner qr = new QueryRunner(ds);
        String sql = "select count(*) from tab_student";
        Number number = (Number)qr.query(sql, new ScalarHandler() );
        int cnt = number.intValue(); 
        System.out.println(cnt);
    }
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>

  <default-config>
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql:///web_07</property>
    <property name="user">root</property>
    <property name="password">123</property>
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">20</property>
  </default-config>
  
  <named-config name="oracle"> 
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql:///web_07</property>
    <property name="user">root</property>
    <property name="password">123</property>
  </named-config>
  
</c3p0-config>

c3p0-config.xml 配置文件

#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc
username=root
password=

#<!-- 初始化连接 -->
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 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED

 

 

 

 

 

 

 

 

 

以上是关于jdbc笔记2的主要内容,如果未能解决你的问题,请参考以下文章

关于mysql驱动版本报错解决,Cause: com.mysql.jdbc.exceptions.jdbc4Unknown system variable ‘query_cache_size(代码片段

mysql jdbc源码分析片段 和 Tomcat's JDBC Pool

学习笔记:python3,代码片段(2017)

JDBC学习笔记及问题小结

hibernate-笔记

面试常用的代码片段