JDBC基础知识--Connection、ResultSet、ResultSetMetaData、DatabaseMetaData、日期、元数据、DAO设计模式

Java连接数据库-JDBC(Java DataBase Connectivity):为访问不同的数据库提供了一种统一的途径,为开发者屏蔽了一些细节问题。

一、JDBC使用步骤

1.加载驱动:以使用MYSQL为例

Class.forName("com.mysql.jdbc.Driver");

2.创建连接:

Connection con=DriveManager.getConnection("jdbc:mysql://localhost:3306/数据库名称?characterEncoding=utf-8","username","password");

3.创建执行SQL语句的对象(Statement/PreparedStatement):

1)Statement:

Statement stmt=con.createStatement();

存在问题:注入攻击

用户输入数据中注入非法的 SQL 语句段或命令,从而利用系统的 SQL 引擎完成恶意行为的做法

解决方法:使用PreparedStatement就可以了。而且使用PreparedStatement代码的可读性和可维护性比较好

2)PreparedStatement:PreparedStatement是Statement的子接口,它表示一条预编译过的SQL语句PreparedStatement对象所代表的SQL语句中的参数用问号(?)来表示,调用 PreparedStatement对象的setXXX()方法来设置这些参数。set方法有两个参数,第一个参数是要设置的SQL语句中的参数的索引(从1开始),第二个是设置的SQL语句中的参数的值

因为PreparedStatement是预编译的,所以在多次执行相同的sql语句时速度更快;

//PreparedStatement对SQL语句先预编译,只要将参数直接传入编译过的语句执行代码中就会得到执行。
String sql = "insert into student(sno,sname,sex,height,tel) "+ "values(default,?,?,?,?)";
stmt = conn.prepareStatement(sql);
stmt.setString(2, name);
stmt.setString(3, sex);
stmt.setDouble(4, height);
stmt.setString(5, tel);
stmt.execute();

4.执行SQL语句,得到结果:

int rs=stmt.executeUpdate(sql); //增删改

Resultset re=stme.executeQuery(sql);//查

【注】:PreparedStatement要调用无参数的execute()!!!!!Statement调用有参数的execute(sql)。如果调用PreparedStatement.execute(sql),就白预编译和设置参数了,执行的还是Statement中的execute(sql),可能还会报错。

5.关闭连接:

con.close();
stmt.close();

二、ResultSet

数据库结果集的数据表,通常通过执行查询数据库的语句生成。ResultSet对象具有指向其当前数据行的指针,最初指针被置于第一行之前,next()方法将指针移动到下一行。

其他常用方法:

boolean next():将指针移动到下一行,如果下一行没有记录返回False,否则返回True。

void afterLast():将指针移动到此 ResultSet 对象的末尾,正好位于最后一行之后

boolean last():将指针移动到此 ResultSet 对象的最后一行。

void beforeFirst():将指针移动到此 ResultSet 对象的开头,正好位于第一行之前。

boolean first():将指针移动到此 ResultSet 对象的第一行。

int getXxx(int columnIndex) :以Xxx的形式检索此ResultSet对象的当前行中指定列的值。

int getXxx(String columnName): 以Xxx的形式检索此ResultSet对象的当前行中指定列的值。

int getRow() :检索当前行编号

ResultSetMetaData getMetaData() :检索此 ResultSet 对象的列的编号、类型和属性

三、ResultSetMetaData(结果集元数据)

可用于获取关于ResultSet结果集中列的类型、列名或其他属性信息,存放在ResultSet对象中,因此可以通过re.getMetaData()获得

常用方法:

int getColumnCount():返回此 ResultSet 对象中的列数。

String getColumnName(int column):获取指定列的名称,索引从1开始

String getColumnLabel(int column):获取指定列的别名,索引从1开始

int getColumnType(int column):检索指定列的类型名称

String getColumnTypeName(int column):检索指定列的数据库特定的类型名称。

int getColumnDisplaySize(int column):指示指定列的最大标准宽度,以字符为单位。

String getTableName(int column):获取指定列所在表的名称。

String getCatalogName(int column):获取指定列所在数据库名称。

四、DatabaseMetaData

关于数据库的整体综合信息。

DataBaseMetaData对象是在Connection对象上调用getMetaData获得的。

常用方法:

String getDatabaseProductName() 检索此数据库产品的名称

String getDatabaseProductVersion() 检索此数据库产品的版本号。

int getDatabaseMajorVersion() 检索底层数据库的主版本号。

int getDatabaseMinorVersion() 检索底层数据库的次版本号。

五、多条SQL语句批处理

注意:批处理不同于事务,区分二者的不同。

①Statement

Statement st=conn.createStatement();
st.addBatch(sql1);
st.addBatch(sql2);
st.addBatch(sql3);
st.executeBatch();

②PreparedStatement:只适用于结构相似的语句之间做批处理

PreparedStatement pst=con.preparedStatement(sql1);
for(int i=0;i<100;i++){
    pst.setInt(1,i);
    ....
    pst.addBatch();
}
pst.executeBatch();

六、JDBC的事务控制

 通过Connection来控制事务

conn.setAutoCommit(false);    //取消自动提交事务,手动提交
......
......
conn.commit();    //提交事务
conn.rollback();    //回滚事务

七、日期类型的处理

mysql中表示日期的类型有三个:Date,Time,Timestamp。Data只能表示年月日,Time只能表示时分秒,Timestamp不仅可以表示年月日时分秒,还可以表示到更精确。

java中有同样三个日期类型与之相对应,这三个类型位于java.sql包中。并且这三个类都是java.util.Date的子类。

八、获得数据库自动生成的主键

在创建PreparedStatement时,指定一个参数autoGeneratedKeys,其中autoGeneratedKeys的值为Statement.RETURN_GENERATED_KEYS或者Statement.NO_GENERATED_KEYS

Statement.RETURN_GENERATED_KEYS:将生成的主键作为ResultSet返回到PrepareStatement中,因为可能一次插入多条数据,所以结果存储在ResultSet。

Statement.NO_GENERATED_KEYS:则不返回生成的主键

PreparedStatement ps = con.prepareStatement(String sql,int autoGeneratedKeys);
ResultSet rs = ps.getGeneratedKeys();    

使用Statement也可以指定参数来获得自动生成的主键,只不过是在execute(String sql,int autoGeneratedKeys)或executeUpdate(String sql,int autoGeneratedKeys)时指定是否返回主键。

九、DAO设计模式

Data Access Object,数据存取对象,是一种用来操作数据库的设计模式,就是将数据库操作都封装起来,对外提供相应的接口

一个典型的DAO模式应该包括以下几个部分:

       VO(value object):只包含值(属性),就是对数据库中某个表的映射

       DAO接口:只包含方法,就是对于VO中的属性进行的各种操作(增删改查等)。还可以进一步分为BaseDao类 和一般Dao接口,BaseDao类中定义一些基本的数据库连接、资源关闭、SQL语句的执行等基本操作,这样DAO实现类中只需要继承BaseDao类,并实现一般Dao接口就可以。

       DAO实现类:方法的具体实现

好处:

1、隔离了数据访问代码和业务逻辑代码。业务逻辑代码直接调用DAO方法即可,完全感觉不到数据库表的存在。分工明确,数据访问层代码变化不影响业务逻辑代码,这符合单一职能原则,降低了藕合性,提高了可复用性。
2、隔离了不同数据库实现。采用面向接口编程,如果底层数据库变化,如由 MySQL 变成 Oracle 只要增加 DAO 接口的新实现类即可,原有 MySQL 实现不用修改,提高了代码扩展性和系统的可移植性。

实例:数据库中有一个存储图书信息的表,表结构和表数据如图所示,分别为图书编号,书名和价格。对其进行DAO封装

项目目录结构:其中vo包中的Book类对应数据库中的book信息表。book表中有几个字段,Book类中就有几个属性

                         BaseDao中定义了数据库连接、资源关闭、执行SQL语句(采用可变参数将SQL语句的参数传入)

                         BookDao接口中定义了需要对book表进行的操作,包括插入图书、删除图书、修改图书,查询比较麻烦,分为很多不同的种类,这里只写了最简单的查询情况,即查询所有图书、按编号查询图书和分页查询图书 。

                         BookDaoImpl作为DAO实现类,需要实现BookDao接口中定义的方法,完成具体的操作语句,这样在使用时,直接调用并将图书信息作为参数传入即可。对于调用者来说,并不需要使用到JDBC。

                         TestDAO用于测试,模拟使用者直接调用BookDaoImpl中的方法即可。

代码:

Book.java

package Test.com.oracle.vo;

public class Book {
    private Integer isbn;
    private String bookname;
    private Integer price;

    public Integer getIsbn() {
        return isbn;
    }
    public void setIsbn(Integer isbn) {
        this.isbn = isbn;
    }
    public String getBookname() {
        return bookname;
    }
    public void setBookname(String bookname) {
        this.bookname = bookname;
    }
    public Integer getPrice() {
        return price;
    }
    public void setPrice(Integer price) {
        this.price = price;
    }

    public Book() {
        super();
    }

    public Book(String bookname, Integer price) {
        this.bookname = bookname;
        this.price = price;
    }

    public Book(Integer isbn, String bookname, Integer price) {
        this.isbn = isbn;
        this.bookname = bookname;
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "isbn=" + isbn +
                ", bookname='" + bookname + '\'' +
                ", price=" + price +
                '}';
    }
}

BaseDao.java

package Test.com.oracle.dao;

import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BaseDao {
    /**
     * 获得数据库连接
     * @return
     */
    public Connection getConnection() {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        String url = "jdbc:mysql://localhost:3306/oracle?characterEncoding=utf-8";
        String user = "root";
        String pwd = "root";
        Connection con = null;
        try {
            con = DriverManager.getConnection(url, user, pwd);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return con;
    }

    /**
     * 关闭资源,可以关闭一切实现了AutoCloseable接口的
     * 例如Connection,ResultSet,PreparedStatement等
     *
     * @param con
     */
    public void close(AutoCloseable con) {
        if (con != null) {
            try {
                con.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 动态执行SQL语句(主要是增删改),使用可变参数
     * 可变参数使用时的方法与数组相同
     * 注意:一个方法至多只能有一个可变参数,且需要作为最后一个参数
     *
     * @param sql
     * @param objs
     */
    public void executeSql(String sql, Object... objs) {
        Connection con = this.getConnection();
        PreparedStatement ps = null;
        try {
            ps = con.prepareStatement(sql);
            //设置执行的参数
            for (int i = 0; i < objs.length; i++) {
                ps.setObject(i + 1, objs[i]);
            }
            ps.execute();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            this.close(ps);
            this.close(con);
        }
    }

    /**
     * 动态执行SQL查询语句,并将返回结果封装到List中
     * 每条记录对应List中的一个Map,
     *
     * @param sql
     * @param objs
     * @return
     */
    public List<Map<String, Object>> executeQuery(String sql, Object... objs) {
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        Connection conn = this.getConnection();
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < objs.length; i++) {
                ps.setObject(i + 1, objs[i]);
            }
            rs = ps.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();
            while (rs.next()) {
                Map<String, Object> map = new HashMap<String, Object>();
                for (int i = 1; i <= rsmd.getColumnCount(); i++) {
                    map.put(rsmd.getColumnLabel(i), rs.getObject(i));
                }
                list.add(map);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            this.close(rs);
            this.close(ps);
            this.close(conn);
        }
        return list;
    }

}

BookDao.java

package Test.com.oracle.dao;

import Test.com.oracle.vo.Book;

import java.util.List;

public interface BookDao {

    public void insert(Book book);

    public void update(Book book);

    public void delete(int isbn);

    public void delete(int[] isbn);

    public List<Book> getAll();

    public Book getBookById(int isbn);

    public List<Book> getAllByPage(int pageNumber,int pageSize);

}

BookDaoImpl.java

package Test.com.oracle.dao;

import Test.com.oracle.vo.Book;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


public class BookDaoImpl extends BaseDao implements BookDao {

    @Override
    public void insert(Book book) {
        executeSql("insert into book values(null,?,?)",book.getBookname(),book.getPrice());
    }

    @Override
    public void update(Book book) {
        executeSql("update book set bookname=?,price=? where isbn=?",book.getBookname(),book.getPrice(),book.getIsbn());
    }

    @Override
    public void delete(int isbn) {
        executeSql("delete from book where isbn=?",isbn);
    }

    //批量删除
    public void delete(int[] isbn) {

    }

    @Override
    public List<Book> getAll() {
        List<Map<String,Object>> list = executeQuery("select * from book");

        return convert(list);
    }

    @Override
    public Book getBookById(int isbn) {
        List<Map<String,Object>> list = executeQuery("select * from book where isbn=?", isbn);
        return list.isEmpty()?null:convert(list).get(0);
    }

    /**
     * pageSize为一页显示几本书
     * pageNumber为当前显示的是第几页
     * @param pageNumber
     * @param pageSize
     * @return
     */
    @Override
    public List<Book> getAllByPage(int pageNumber, int pageSize) {
        List<Map<String,Object>> list = executeQuery("select * from book order by isbn limit ?,?",
                (pageNumber-1)*pageSize,
                 pageSize);
        return convert(list);
    }


    public List<Book> convert(List<Map<String,Object>> list){
        List<Book> bList = new ArrayList<Book>();

        for(Map<String,Object> map:list){
            Book b = new Book();
            b.setIsbn((int)map.get("isbn"));
            b.setBookname((String)map.get("bookname"));
            b.setPrice((int)map.get("price"));
            bList.add(b);
        }
        return bList;
    }

}

TestDao.java

package Test.com.oracle;

import Test.com.oracle.dao.BookDao;
import Test.com.oracle.dao.BookDaoImpl;
import Test.com.oracle.vo.Book;
import java.util.List;

public class TestDAO {
    public static void main(String[] args) {
        Book b = new Book("活着就是为了改变世界",357);
        b.setIsbn(2);
        BookDao dao = new BookDaoImpl();
        dao.insert(b);
        dao.delete(2);
        dao.delete(8);


//        BookDao dao = new BookDaoImpl();
//        List<Book> book = dao.getAll();
//        for(Book b:book){
//            System.out.println(b);
//        }
//
//
//        BookDao dao = new BookDaoImpl();
//        Book res = dao.getBookById(101);
//        if(res!=null){
//            System.out.println(res);
//        }else{
//            System.out.println("不存在这本书");
//        }
//
//
//        BookDao dao = new BookDaoImpl();
//
//        List<Book> book = dao.getAllByPage(2,10);
//        for(Book b:book){
//            System.out.println(b);
//        }
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值