jdbc基础知识(三)
来源:互联网 发布:淘宝客服幽默常用语 编辑:程序博客网 时间:2024/05/18 01:27
一、简介
- JDBC(Java Data Base Connectivity,java数据库连接),由一些接口和类构成的API。
- J2SE的一部分,由java.sql,javax.sql包组成。
- 应用程序、JDBC API、数据库驱动及数据库之间的关系
连接数据库的步骤:
- 注册驱动(只需一次)
- 建立连接(Connection)
- 创建可执行SQL语句(Statement)
- 执行语句
- 处理执行结果(ResultSet)
- 释放资源
注册驱动的几种方法:
- Class.forName(com.mysql.jdbc.Driver); 不会对具体的驱动产生依赖
- DriverManager.registerDriver(com.mysql.jdbc.Driver);会造成DriverManager中产生两个一样的驱动,并会对具体的驱动类产生依赖。
- System.setProperty(“jdbc.drivers”, “driver1:driver2”);虽然不会对具体的驱动类产生依赖;但注册不太方便,所以很少使用。
建立连接
Connecttion conn=DriverManger.getConnection(url,user,password); - URL格式:
jdbc:子协议:子名称//主机名:端口/数据库?属性名=属性值&… - User,password可以用“属性名=属性值”方式告诉数据库;
- 其他参数如:useUnicode=true&characterEncoding=GBK。
创建执行的SQL语句 - Statement
Statement st=conn.creatStatement(); st.executeQuery(sql);
- PreparedStatemnet
String sql=select * from table_name where col_name =?;PreparedStatement ps=conn.preparedStatement(sql);ps.setString(1,"col_value");ps.executeQuery();
处理执行结果
ResultSet rs=statement.executeQuery(sql);while(rs.next()){ rs.getString("col_name"); rs.getInt(l_name"); //...}
释放资源
释放ResultSet, Statement,Connection.
数据库连接(Connection)是非常稀有的资源,用完后必须马上释放,如果Connection不能及时正确的关闭将导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放。
基本的CRUD(创建、读取、更新、删除)
模板代码
Connection conn = null;Statement st=null;ResultSet rs = null;try { //获得Connection //创建Statement //处理查询结果ResultSet} finally { //释放资源ResultSet, Statement,Connection}
创建
增加对应SQL的INSERT,返回增加成功的行(记录)数
conn=getConnection();Statement st=conn.createStatement();String sql="insert into user(name,age,regist_date)"+"values('name',10,now());int i=st.executeUpdate(sql);//i为插入的记录数
读取
读取对应sql的select,返回查询结果
conn=getConnection();st=conn.createStatement();String sql="select id,name,regist_date from user ";ResultSet rs=st.executeQuery(sql);while (rs.next()) { System.out.print(rs.getInt("id") + " \t\t "); System.out.print(rs.getString("name") + " \t\t "); System.out.print(rs.getInt("age") + " \t\t "); System.out.print(rs.getTimestamp("regist_date") + " \t\t "); System.out.println();}
更新
更新(修改)对应SQL的UPDATE,返回被修改的行(记录)数
conn = getConnection();Statement st = conn.createStatement();String sql=“update person set name='new name‘”;int i = st.executeUpdate(sql);//i为符合条件的记录数
删除
删除对应SQL的DELETE,返回被删除的行(记录)数
conn = getConnection();Statement st = conn.createStatement();String sql=“delete from user where id=1”;int i = st.executeUpdate(sql);//i为删掉的记录数
增删改查总结
- 增删改用Statement.executeUpdate(sql)来完成,返回整数(匹配的记录数)
- 查使用Statement.executeQuery(sql);来完成返回的是ResultSet对象,ResultSet中包含了查询的结果;查询相对与增、删、改要复杂一些,因为有查询结果要处理。
SQL注入,PreparedStatement和Statement - 在SQL中包含特殊字符或SQL的关键字(如:’ or 1 or
‘)时Statement将出现不可预料的结果(出现异常或查询的结果不正确),可用PreparedStatement来解决。
PreperedStatement(从Statement扩展而来)相对Statement的优点:
- 1.没有SQL注入的问题。
- 2.Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出。
- 3.数据库和驱动可以对PreperedStatement进行优化(只有在相关联的数据库连接没有关闭的情况下有效)。
数据类型 - 详细信息见java.sql.Types
- 几种特殊且比较常用的类型
1.DATA,TIME,TIMESTAMP date,time,datetime存:ps.setDate(i,d); ps.setTime(i,t); ps.setTimestamp(i, ts); 取:rs.getDate(i); rs.getTime(i); rs.getTimestamp(i); 2.CLOB text 存:ps.setCharacterStream(index, reader, length); ps.setString(i, s); 取:reader = rs. getCharacterStream(i); reader = rs.getClob(i).getCharacterStream(); string = rs.getString(i); 3.BLOB blob 存:ps.setBinaryStream(i, inputStream, length); 取:rs.getBinaryStream(i); rs.getBlob(i).getBinaryStream();
一个简单用户相关的数据访问层
- J2EE三层架构简介 表示层 、业务逻辑层、数据访问层,三层之间用接口隔离。
- 定义domain对象User,定义存取用户的接口
- 用JDBC实现接口
- 用配置文件(properties)和反射实现与具体类的耦合
事务(ACID) - 原子性(atomicity):组成事务处理的语句形成了一个逻辑单元,不能只执行其中的一部分
- 一致性(consistency):在事务处理执行前后,数据库是一致的(两个账户要么都变,或者都不变)。
- 隔离性(isolcation):一个事务处理对另一个事务处理没有影响。
- 持续性(durability):事务处理的效果能够被永久保存下来 。
- connection.setAutoCommit(false);//打开事务。
- connection.commit();//提交事务。
- connection.rollback();//回滚事务。
隔离级别多线程并发读取数据时的正确性
- connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
- V:可能出现,X:不会出现
隔离级别 脏读 不可重复读 幻读
读未提交(Read uncommitted) V V V
读已提交(Read committed) x V V
可重复读(Repeatable read) x x V
可串行化(Serializable ) x x x
存储过程
存储过程
CallableStatement(从PreperedStatement扩展来)cs = connection.prepareCall(“{call psname(?,?,?)}”);cs.registerOutParameter(index, Types.INTEGER);cs.setXXX(i, xxxx);cs.executeUpdate();int id=cs.getInt(index);
其他的几个API
Statement.getGeneratedKeys() PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); ps.executeUpdate(); ResultSet rs = st.getGeneratedKeys();rs.getInt(1);批处理,可以大幅度提升大量增、删、改的速度。 PreparedStatement.addBatch(); PreparedStatement.executeBatch();可滚动的结果集 Statement st = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = st.executeQuery(sql); rs.beforeFirst(); rs.afterLast();rs.first();rs.isFirst();rs.last();rs.isLast(); rs.absolute(9);rs.moveToInsertRow();
DatabaseMetaData
- DatabaseMetaData meta = connection.getMetaData();
- 通过DatabaseMetaData可以获得数据库相关的信息如:数据库版本、数据库名、数据库厂商信息、是否支持事务、是否支持某种事务隔离级别,是否支持滚动结果集等。
ResultSetMetaData - ResultSetMetaData meta = rs.getMetaData();
- 通过ResultSetMetaData可以获得结果有几列、各列名、各列别名、各列类型等。
- 可以将ResultSet放入Map(key:列名 value:列值)。
用反射ResultSetMetaData将查询结果读入对象中(简单的O/RMapping)
1)让SQL语句中列别名和要读入的对象属性名一样;
2)通过ResultSetMetaData获得结果列数和列别名;
3)通过反射将对象的所有setXxx方法找到;
4)将3)找到的方法setXxx和2)找到的列别名进行匹配(即方法中的xxx于列别名相等);
5)由上一步找到的方法和列别名对应关系进行赋值Method.invoke(obj, rs.getObject(columnAliasName));
数据源和连接池
- DataSource用来取代DriverManager来获取Connection;
- 通过DataSource获得Connection速度很快;
- 通过DataSource获得的Connection都是已经被包裹过的(不是驱动原来的连接),他的close方法已经被修改。
- 一般DataSource内部会用一个连接池来缓存Connection,这样可以大幅度提高数据库的访问速度;
- 连接池可以理解成一个能够存放Connection的Collection;
- 我们的程序只和DataSource打交道,不会直接访问连接池;
一个简单的数据源实现
使用装饰模式的Connection(核心代码)
class MyConnection implements Connection{ private Connection realConn; private LinkedList connPool; MyConnection(Connection rConn, LinkedList cPool){ this.realConn=rConn; this.connPool=cPool; } public void close(){ this.connPool.addLast(this); }
DataSource(核心代码)
class MyDataSource implements DataSource{ private LinkedList connPool = new Vector(); public Connection getConneciton (){ if(this.connPool.size()>0) return this.connPool.removeFirst(0); return createConnection(); } private Connection createConnection(){ Connection realConn = DriverManager.getConnection(); Connection myConn = new MyConnection(realConn,this.connPool); return myConn; } //…. }
常用的开源实现DBCP
使用DBCP必须用的三个包: commons-dbcp-1.2.1.jar, commons-pool-1.2.jar, commons-collections-3.1.jar。Java API: BasicDataSourceFactory.createDataSource(properties);
具体实践
import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;public class Base { /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { template(); } static void template() throws Exception { Connection conn = null; Statement st = null; ResultSet rs = null; try { // 2.建立连接 conn = JdbcUtils.getConnection(); // conn = JdbcUtilsSing.getInstance().getConnection(); // 3.创建语句 st = conn.createStatement(); // 4.执行语句 rs = st.executeQuery("select * from user"); // 5.处理结果 while (rs.next()) { // 参数中的1,2,3,4是指sql中的列索引 System.out.println(rs.getObject(1) + "\t" + rs.getObject(2) + "\t" + rs.getObject(3) + "\t" + rs.getObject(4)); } } finally { JdbcUtils.free(rs, st, conn); } } static void test() throws SQLException, ClassNotFoundException { // 1.注册驱动 DriverManager.registerDriver(new com.mysql.jdbc.Driver()); System.setProperty("jdbc.drivers", "com.mysql.jdbc.Driver"); Class.forName("com.mysql.jdbc.Driver");// 推荐方式 // 2.建立连接 String url = "jdbc:mysql://localhost:3306/jdbc"; String user = "root"; String password = ""; Connection conn = DriverManager.getConnection(url, user, password); // 3.创建语句 Statement st = conn.createStatement(); // 4.执行语句 ResultSet rs = st.executeQuery("select * from user"); // 5.处理结果 while (rs.next()) { System.out.println(rs.getObject(1) + "\t" + rs.getObject(2) + "\t" + rs.getObject(3) + "\t" + rs.getObject(4)); } // 6.释放资源 rs.close(); st.close(); conn.close(); }}
- jdbc基础知识(三)
- JDBC基础知识(备忘)
- JDBC基础知识
- JDBC基础知识
- JDBC基础知识
- JDBC基础知识
- JDBC基础知识
- JDBC基础知识
- JDBC基础知识
- JDBC基础知识
- jdbc基础知识
- JDBC 概述(三)
- JDBC 概述(三)
- JDBC 概述(三)
- JDBC 概述(三)
- JDBC基础(三)
- jdbc详解(三)
- jdbc详解(三)
- scala学习-scala中的特殊符号使用
- 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数
- Java如何捕获线程异常?
- Node.js使用递归实现遍历文件夹中所有文件
- Android App加固原理分析
- jdbc基础知识(三)
- STL之简介
- Cookie/Session机制详解
- JMS ActiveMQ入门
- Samba服务安装与配置
- iwebshop 简介
- React+webpack 的开发环境配置步骤(三)
- IO流--File类的使用
- 安卓在Service中弹出Dialog