- 浏览: 496694 次
- 性别:
- 来自: OnePiece
文章分类
- 全部博客 (196)
- --------- 基础----------- (0)
- java 碎碎念 (12)
- java 并行编程 (11)
- java I/O (6)
- java Charset & Encoding (2)
- spring学习笔记 (8)
- 正则表达式 (5)
- web前端-javascript (11)
- web前端-jQuery (7)
- web前端-碎碎念 (1)
- mybatis (0)
- 数据库-通用 (8)
- 数据库-oracle (20)
- nosql-redis (11)
- nosql-mongoDB (1)
- xml (2)
- log4j (2)
- uml (3)
- web services: soap/wsdl (6)
- soa-tuscany (2)
- linux (6)
- ----------修养----------- (0)
- 深入理解java虚拟机 (7)
- java 设计模式 (9)
- 数据结构和算法 (2)
- 读书笔记--代码整洁之道 (2)
- 计算机基础 (1)
- -----------践行---------- (0)
- 重构(refactor) (7)
- jvm-诊断 (4)
- 数据库-让oracle跑得更快 (7)
- Nginx (6)
- ehcache (2)
- 短信开发 (1)
- Servlet+Filter+Listener (2)
- 运维 (6)
- 问题记录 (38)
- 杂七杂八 (12)
最新评论
-
zhanggang807:
第二种方法比较好
<spring> 定时任务每次都执行两次的问题,慎用new ClassPathXmlApplicationContext() -
assasszt:
谢谢分享,很清楚的讲明了原理。
字符集与字符编码简介 -
su0nils000:
难得的笔记
<进阶-2> 打造高效正则表达式 -
足至迹留:
mini188 写道用MD5来解决碰撞是不是也是可行的呢?个人 ...
Hash简介 -
mini188:
用MD5来解决碰撞是不是也是可行的呢?
Hash简介
本来是正写着spring系列,到了spring对DAO的支持部分觉得还是应该先简单回顾下jdbc基础。最后再提起一下DataSource和JNDI。
一、jdbc简介
JDBC就是Java语言访问数据库的一种规范,是一套API,JDBC (Java Database Connectivity) API,即Java数据库编程接口,是一组标准的Java语言中的接口和类,使用这些接口和类,Java客户端程序可以访问各种不同类型的数据库。比如建立数据库连接、执行SQL语句进行数据的存取操作。
JDBC规范采用接口和实现分离的思想设计了Java数据库编程的框架。接口包含在java.sql及javax.sql包中,其中java.sql属于JavaSE,javax.sql属于JavaEE。这些接口的实现类叫做数据库驱动程序,由数据库的厂商或其它的厂商或个人提供。
为了使客户端程序独立于特定的数据库驱动程序,JDBC规范建议开发者使用基于接口的编程方式,即尽量使应用仅依赖java.sql及javax.sql中的接口和类。
简单地说,JDBC 可做三件事:与数据库建立连接,发送 SQL 语句,处理结果。
JDBC 是一种低级 API ,是高级 API 的基础。JDBC 是个“低级”接口,也就是说,它用于直接调用 SQL 命令。在这方面它的功能极佳,并比其它的数据库连接 API 易于使用,但它同时也被设计为一种基础接口,在它之上可以建立高级接口和工具。
JDBC最大的特点是独立于具体的关系数据库,要通过JDBC来存取某一特定的数据库,必须有相应的JDBC Driver,这往往是生产数据库的厂商提供,是连接JDBC API与具体数据库的桥梁。
JDBC驱动程序的四种类型:
1. 第一种类型的驱动程序的实现是通过将JDBC的调用全部委托给其它编程接口来实现的,比如ODBC。这种类型的驱动程序需要安装本地代码库,即依赖于本地的程序,所以便携性较差。比如JDBC-ODBC桥驱动程序。
调用顺序:
Application->JDBC-ODBC->JDBC-ODBC Library->ODBC Driver->DB
适用于快速的原型系统和没有提供JDBC驱动的数据库,如Access.
2. 第二种类型的驱动程序的实现是部分基于Java语言的。即该驱动程序一部分是用Java语言编写,其它部分委托本地的数据库的客户端代码来实现。同类型1的驱动一样,该类型的驱动程序也依赖本地的程序,所以便携性较差.
调用顺序:
Application->JDBC Driver2->Native DataBase Library->DB
3. 第三种类型的驱动程序的实现是全部基于JAVA语言的。该类型的驱动程序通常由某个中间件服务器提供,这样客户端程序可以使用数据库无关的协议和中间件服务器进行通信,中间件服务器再将客户端的JDBC调用转发给数据库进行处理
调用顺序:
Application->JDBC Driver3->Java middleware->JDBC Driver->DB
4. 第四种类型的驱动程序的实现是全部基于JAVA语言的。该类型的驱动程序中包含了特定数据库的访问协议,使得客户端可以直接和数据库进行通信
调用顺序:
Application->JDBC Driver4->database Engine->DB
JDBC 相关的类:
DriverManager:驱动程序管理器。这个是一个实现类,它是一个工厂类,用来生产Driver对象的,这个类的结构设计模式为工厂方法。
Driver:这是驱动程序对象的接口,它指向一个实实在在的数据库驱动程序对象,那么这个数据库驱动程序对象是从哪里来的呢?
DriverManager工厂中有个方法:getDriver(String URL),通过这个方法可以得到驱动程序对象,这个方法是在各个数据库厂商按JDBC规范设计的数据库驱动程序包里的类中静态实现的,也就是在静态块中。
Connection:这个接口可以制向一个数据库连接对象,那么如何得到这个连接对象呢?
是通过DriverManager工厂中的getConnection(String URL)方法得到的
Statement:用于执行静态的SQL语句的接口,通过Connection中的createStatement方法得到的
Resultset:用于指向结果集对象的接口,结果集对象是通过Statement中的execute等方法得到的
二、jdbc的典型使用方法
JDBC 操作数据库的一般步骤:
1) 注册驱动(应用程序启动只做一次)
2) 建立连接(Connection)
3) 创建执行sql的语句(Statement, PreStatement)
4) 执行语句(增删改查)
5) 处理执行结果(ResultSet)
6) 释放资源
1. 注册驱动
从上面的介绍可以看出,程序要与任何数据库连接都要有相应的驱动程序。这个驱动程序需要注册到能被驱动程序管理器(DriverManager)找到。
DriverManager类包含一列Driver类,它们已通过调用方法DriverManager.registerDriver对自己进行了注册。所有Driver类都必须包含有一个静态部分。它创建该类的实例,然后在加载该实例时DriverManager类进行注册。这样,用户正常情况下将不会直接调用DriverManager.registerDriver;而是在加载驱动程序时由驱动程序自动调用。
有三种方式注册驱动,其中第一种是推荐的方式,另两种仅作了解:
1)最常用的方式(这将显式地加载驱动程序类。由于这与外部设置无关,因此推荐使用这种加载驱动程序的方法)
Class.forName(“com.mysql.jdbc.Driver”); // 以mysql驱动做示例。
2)直接创建对象
new com.mysql.jdbc.Driver();//创建driver对象,加载数据库驱动
String url="jdbc:mysql://localhost:3306/databasename";//数据库连接子协议
Connection conn=DriverManager.getConnection(url,"username","password");
不推荐理由:由new com.mysql.jdbc.Driver()可以知道,这里需要创建一个类的实例。创建类的实例就需要在java文件中将该类通过import导入,否则就会报错,即采用这种方式,程序在编译的时候不能脱离驱动类包,为程序切换到其他数据库带来麻烦
3) 设置系统属性
System.setProperty("jdbc.driver","com.mysql.jdbc.Driver");//系统属性指定数据库驱动
String url="jdbc:mysql://localhost:3306/databasename";//数据库连接子协议
Connection conn=DriverManager.getConnection(url,"username","password");
可以同时导入多个jdbc驱动,中间用冒号“:”分开,比如:
System.setProperty("jdbc.drivers","XXXDriver:XXXDriver:XXXDriver");
这样就一次注册了三个数据库驱动。
注:新加载的 Driver 类都要通过调用 DriverManager.registerDriver() 类进行自我注册,但实际使用中都不需要显式调用,因为这三种方式都采用自己的方式自动调用了这个注册函数。比如第二种方式:
com.mysql.jdbc.Driver类的静态代码快里面已经进行了修改的操作
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E)
{
throw new RuntimeException("Can't register driver!");
}
}
DriverManager是一个驱动管理器,内部有一个驱动注册表,map结构,可以向其注册多个驱动。
2. 建立连接
Connection 对象代表与数据库的连接。连接过程包括所执行的 SQL 语句和在该连接上所返回的结果。一个应用程序可与单个数据库有一个或多个连接,或者可与许多数据库有连接。打开连接与数据库建立连接的标准方法是调用DriverManager.getConnection方法。该方法接受含有某个 URL 的字符串。DriverManager 类(即所谓的 JDBC管理层)将尝试找到可与那个 URL 所代表的数据库进行连接的驱动程序。DriverManager 类存有已注册的 Driver 类的清单。当调用方法 getConnection 时,它将检查清单中的每个驱动程序,直到找到可与URL 中指定的数据库进行连接的驱动程序为止。Driver 的方法connect 使用这个 URL来建立实际的连接。
建立连接方法:
String url="jdbc:mysql://localhost:3306/databasename";//数据库连接子协议
Connection conn=DriverManager.getConnection(url,"username","password");
Jdbc url规范:
Jdbc 的url遵循一定的规范,jdbc:< 子协议 >:< 子名称 >
JDBC URL 的三个部分可分解如下:
(1)jdbc --协议。JDBC URL 中的协议总是 jdbc。
(2)<子协议> -- 驱动程序名或数据库连接机制(这种机制可由一个或多个驱动程序支持)的名称。子协议名的典型示例是 "odbc",该名称是为用于指定 ODBC 风格的数据资源名称的 URL 专门保留的。例如,为了通过JDBC-ODBC 桥来访问某个数据库,可以用如下所示的 URL:
jdbc:odbc:fred
本例中,子协议为 "odbc",子名称 "fred" 是本地ODBC 数据资源。
如果要用网络命名服务(这样 JDBC URL 中的数据库名称不必是实际名称),则命名服务可以作为子协议。例如,可用如下所示的 URL :jdbc:dcenaming:accounts-payable本例中,该 URL 指定了本地 DCE 命名服务应该将数据库名称 "accounts-payable" 解析为更为具体的可用于连接真实数据库的名称。
(3)<子名称> -- 一种标识数据库的方法。子名称可以依不同的子协议而变化。它还可以有子名称的子名称(含有驱动程序编程员所选的任何内部语法)。使用子名称的目的是为定位 数据库提供足够的信息。前例中,因为 ODBC 将提供其余部份的信息,因此用 "fred" 就已足够。然而,位于远程服务器上的数据库需要更多的信息。例如,如果数据库是通过Internet 来访问的,则在 JDBC URL 中应将网络地址作为子名称的一部份包括进去,且必须遵循如下所示的标准 URL 命名约定://主机名:端口/子协议假设 "dbnet" 是个用于将某个主机连接到 Internet 上的协议,则 JDBC URL 类似:
jdbc:dbnet://wombat:356/fred
特殊的"odbc" 子协议
子协议odbc 是一种特殊情况。它是为用于指定 ODBC 风格的数据资源名称的 URL 而保留的,并具有下列特性:允许在子名称(数据资源名称)后面指定任意多个属性值。odbc 子协议的完整语法为: jdbc:odbc:< 数据资源名称 >[;< 属性名 >=< 属性值 >]*
因此,以下都是合法的 jdbc:odbc 名称:
jdbc:odbc:qeor7jdbc:odbc:wombat
jdbc:odbc:wombat;CacheSize=20;ExtensionCase=LOWER
jdbc:odbc:qeora;UID=kgh;PWD=fooey
一些典型db的配置示例可以参考:
http://blog.csdn.net/ring0hx/article/details/6152528
注:oracle中连接和会话的概念,jdbc中的Connection对应oracle中的会话,而不是连接。
Oracle连接又分两种,从jdbc url可以看出配置的不同,一种是thin连接,一种是OCI,区别在性能和对集群的支持上,可以参考:
http://wyf289283641.iteye.com/blog/1911274
3.创建statement
Statement 对象用于将 SQL 语句发送到数据库中。实际上有三种 Statement 对象,它们都作为在给定连接上执行 SQL 语句的包容器:Statement、PreparedStatement(它从 Statement 继承而来)和 CallableStatement(它从 PreparedStatement 继承而来)。它们都专用于发送特定类型的 SQL 语句:
(1)Statement 对象用于执行不带参数的简单 SQL 语句;
(2)PreparedStatement 对象用于执行带或不带 IN 参数的预编译 SQL 语句;能有效防止sql注入和较好的执行效率。
注:所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作,其主要原因是程序没有细致地过滤用户输入的数据,致使非法数据侵入系统。可以通过使用PreparedStatement, 绑定变量等方式防止sql注入。具体相关内容需要查询专业书籍或其他资料。
(3)CallableStatement 对象用于执行对数据库有存储过程的调用。
下面分别是三种statement的创建方法:
1)Statement创建
Connection con = DriverManager.getConnection(url, "sunny", "");
Statement stmt = con.createStatement();
2)PreparedStatement创建
PreparedStatement 实例包含已编译的 SQL 语句。这就是使语句“准备好”。包含于 PreparedStatement 对象中的 SQL 语句可具有一个或多个 IN 参数。IN参数的值在 SQL 语句创建时未被指定。相反的,该语句为每个 IN 参数保留一个问号(“?”)作为占位符。每个问号的值必须在该语句执行之前,通过适当的setXXX 方法来提供。
由于 PreparedStatement 对象已预编译过,所以其执行速度要快于 Statement 对象。因此,多次执行的 SQL 语句经常创建为 PreparedStatement 对象,以提高效率。
PreparedStatement pstmt = con.prepareStatement("UPDATE table4 SET m = ? WHERE x = ?");
pstmt.setLong(1, 123456789); //1代表占位符的顺序,第一个占位符。
pstmt.setLong(2, 100000000);
3) CallableStatement ,这个用到的场景不多,本人没有用过。可以参考:
http://dev.yesky.com/SoftChannel/72342371961929728/20040917/1855399.shtml
4.处理结果
ResultSet 包含符合 SQL 语句中条件的所有行,并且它通过一套 get 方法(这些 get 方法可以访问当前行中的不同列)提供了对这些行中数据的访问。ResultSet.next 方法用于移动到 ResultSet 中的下一行,使下一行成为当前行。
java.sql.Statement stmt = conn.createStatement();
ResultSet r = stmt.executeQuery("SELECT a, b, c FROM Table1");
while (r.next())
{
// 打印当前行的值。
int i = r.getInt("a");
String s = r.getString("b");
float f = r.getFloat("c");
System.out.println("ROW = " + i + " " + s + " " + f);
}
ResultSet 维护指向其当前数据行的光标。每调用一次 next 方法,光标向下移动一行。最初它位于第一行之前,因此第一次调用 next 将把光标置于第一行上,使它成为当前行。随着每次调用 next 导致光标向下移动一行,按照从上至下的次序获取ResultSet 行。
在 ResultSet 对象或其父辈 Statement 对象关闭之前,光标一直保持有效。
在 SQL 中,结果表的光标是有名字的。如果数据库允许定位更新或定位删除,则需要将光标的名字作为参数提供给更新或删除命令。可通过调用方法getCursorName 获得光标名。
5.释放资源
数据库使用完毕需要释放资源,这些资源都是系统有限的宝贵资源,必须释放。释放jdbc资源的顺序RestltSet,Statement,Connection,基本是保证用完就关闭。其中Connection最重要,一定要关闭(线程池里连接的创建和关闭由池来管理,不需要程序员干预生命周期)。Connection关闭后ResultSet, Statement会自动关闭(但资源不会立即释放)。
Connection的使用原则是尽量晚创建,尽量早释放。
在关闭资源异常时,应该将资源赋null, 确保资源最大可能的被释放。(GC去回收)
6.处理事务
数据库的事务特性ACID,隔离级别这些本篇先不梳理了,后面梳理oracle时会单独整理。我们在使用时用的最多的是自动提交的设置。
Connection conn = DriverManager.getConnection();
conn.setAutocommit(false); // 关闭自动提交,这种是推荐的做法
//数据库操作
…
conn.commit(); //前面关闭了自动提交,这里就要自己控制提交或回滚(conn.rollback())
可以参考:
http://blog.csdn.net/chenyongsuda/article/details/5641412
事务还可分为本地事务和分布式事务,可以参考:
http://jackyin5918.iteye.com/blog/1922042
三、DataSource和JNDI(Java Naming and Directory)
1.从上面的内容可以看出,如果要与数据库交互必须要获取数据库连接,上面是通过DriverManager.getConnection("url")获取的,需要把url传进去硬编码。DataSource是sun提供的替代DriverManager的方法,类全名是javax.sql.DataSource。javadoc描述的挺清楚:
* A factory for connections to the physical data source that this
* DataSource object represents. An alternative to the
* DriverManager facility, a DataSource object
* is the preferred means of getting a connection. An object that implements
* the DataSource interface will typically be
* registered with a naming service based on the
* Java Naming and Directory (JNDI) API.
通过DataSource获取Connection比DriverManager更灵活,它可以结合JNDI在配置文件里配置数据库的url,当数据库属性改变时不需要修改代码,只要修改配置文件就可以了。另一个优点就是对数据库连接池的支持了。比如spring的JdbcTemplate就是用DataSource来获取连接。
2.JNDI(Java Naming and Directory Interface)是SUN公司提供的一种标准的Java命名系统接口,JNDI提供统一的客户端API,通过不同的访问提供者接口JNDI SPI的实现,由管理者将JNDI API映射为特定的命名服务和目录系统,使得Java应用程序可以和这些命名服务和目录服务之间进行交互。集群JNDI实现了高可靠性JNDI[8],通过服务器的集群,保证了JNDI的负载平衡和错误恢复。在全局共享的方式下,集群中的一个应用服务器保证本地JNDI树的独立性,并拥有全局的JNDI树。每个应用服务器在把部署的服务对象绑定到自己本地的JNDI树的同时,还绑定到一个共享的全局JNDI树,实现全局JNDI和自身JNDI的联系。
JNDI里最常用的类就是InitialContext(javax.naming.InitialContext).
这样的描述仍然不能理解它的作用,只能通过使用去理解,其实所有的程序都是这样,实践,实践,实践。
3.DataSource和JNDI结合的例子
在Spring框架中有如下3种获得DataSource对象的方法:
1)从JNDI获得DataSource.
2)从第三方的连接池获得DataSource.
3)使用DriverManagerDataSource获得DataSource.
下面分别给出示例:
1)从JNDI获得DataSource.
step1、Spring引用JNDI数据源配置信息:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jcptDataSourceJNDI</value>
</property>
</bean>
jcptDataSourceJNDI是tomcat或者其他应用服务器配置的JNDI.
step2、关于JNDI的配置(tomcat):
修改tomcat目录conf/context.xml文件:
<Resource name="jcptDataSourceJNDI" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10" username="tysp"
password="12345678" driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@192.168.1.35:1521:orcl"/>
step3、通过JNDI获取DataSource:
Context context = new InitialContext();
DataSource ds = (DataSource)context.lookup("java:comp/env/jcptDataSourceJNDI");
2)使用DBCP连接池获取
要在Spring中使用DBCP连接池,需要引入commons-collections.jar、commons-dbcp.jar和commons-pool.jar。
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@192.168.1.35:1521:orcl" />
<property name="username" value="or_meal"></property>
<property name="password" value="or_meal"></property>
<property name="maxActive" value="100"></property>
<property name="maxIdle" value="30"></property>
<property name="maxWait" value="10"></property>
<property name="defaultAutoCommit" value="false"></property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect
</prop>
<prop key="show_sql">true</prop>
<prop key="format_sql">true</prop>
</props>
</property>
<property name="mappingResources">
<list></list>
</property>
</bean>
3)使用DriverManagerDataSource
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>oracle.jdbc.driver.OracleDriver</value>
</property>
<property name="url">
<value>jdbc:oracle:thin:@192.168.1.35:orcl</value>
</property>
<property name="username">
<value>or_meal</value>
</property>
<property name="password">
<value>or_meal</value>
</property>
</bean>
在实际项目中可以选择合适的配置方式。以上三种配置的不同可以参考:
http://blog.csdn.net/junjun16818/article/details/6945598
另外还可以参考资料:
http://blog.csdn.net/jingliangfu/article/details/6036730
http://cyf-123456.iteye.com/blog/408012
一、jdbc简介
JDBC就是Java语言访问数据库的一种规范,是一套API,JDBC (Java Database Connectivity) API,即Java数据库编程接口,是一组标准的Java语言中的接口和类,使用这些接口和类,Java客户端程序可以访问各种不同类型的数据库。比如建立数据库连接、执行SQL语句进行数据的存取操作。
JDBC规范采用接口和实现分离的思想设计了Java数据库编程的框架。接口包含在java.sql及javax.sql包中,其中java.sql属于JavaSE,javax.sql属于JavaEE。这些接口的实现类叫做数据库驱动程序,由数据库的厂商或其它的厂商或个人提供。
为了使客户端程序独立于特定的数据库驱动程序,JDBC规范建议开发者使用基于接口的编程方式,即尽量使应用仅依赖java.sql及javax.sql中的接口和类。
简单地说,JDBC 可做三件事:与数据库建立连接,发送 SQL 语句,处理结果。
JDBC 是一种低级 API ,是高级 API 的基础。JDBC 是个“低级”接口,也就是说,它用于直接调用 SQL 命令。在这方面它的功能极佳,并比其它的数据库连接 API 易于使用,但它同时也被设计为一种基础接口,在它之上可以建立高级接口和工具。
JDBC最大的特点是独立于具体的关系数据库,要通过JDBC来存取某一特定的数据库,必须有相应的JDBC Driver,这往往是生产数据库的厂商提供,是连接JDBC API与具体数据库的桥梁。
JDBC驱动程序的四种类型:
1. 第一种类型的驱动程序的实现是通过将JDBC的调用全部委托给其它编程接口来实现的,比如ODBC。这种类型的驱动程序需要安装本地代码库,即依赖于本地的程序,所以便携性较差。比如JDBC-ODBC桥驱动程序。
调用顺序:
Application->JDBC-ODBC->JDBC-ODBC Library->ODBC Driver->DB
适用于快速的原型系统和没有提供JDBC驱动的数据库,如Access.
2. 第二种类型的驱动程序的实现是部分基于Java语言的。即该驱动程序一部分是用Java语言编写,其它部分委托本地的数据库的客户端代码来实现。同类型1的驱动一样,该类型的驱动程序也依赖本地的程序,所以便携性较差.
调用顺序:
Application->JDBC Driver2->Native DataBase Library->DB
3. 第三种类型的驱动程序的实现是全部基于JAVA语言的。该类型的驱动程序通常由某个中间件服务器提供,这样客户端程序可以使用数据库无关的协议和中间件服务器进行通信,中间件服务器再将客户端的JDBC调用转发给数据库进行处理
调用顺序:
Application->JDBC Driver3->Java middleware->JDBC Driver->DB
4. 第四种类型的驱动程序的实现是全部基于JAVA语言的。该类型的驱动程序中包含了特定数据库的访问协议,使得客户端可以直接和数据库进行通信
调用顺序:
Application->JDBC Driver4->database Engine->DB
JDBC 相关的类:
DriverManager:驱动程序管理器。这个是一个实现类,它是一个工厂类,用来生产Driver对象的,这个类的结构设计模式为工厂方法。
Driver:这是驱动程序对象的接口,它指向一个实实在在的数据库驱动程序对象,那么这个数据库驱动程序对象是从哪里来的呢?
DriverManager工厂中有个方法:getDriver(String URL),通过这个方法可以得到驱动程序对象,这个方法是在各个数据库厂商按JDBC规范设计的数据库驱动程序包里的类中静态实现的,也就是在静态块中。
Connection:这个接口可以制向一个数据库连接对象,那么如何得到这个连接对象呢?
是通过DriverManager工厂中的getConnection(String URL)方法得到的
Statement:用于执行静态的SQL语句的接口,通过Connection中的createStatement方法得到的
Resultset:用于指向结果集对象的接口,结果集对象是通过Statement中的execute等方法得到的
二、jdbc的典型使用方法
JDBC 操作数据库的一般步骤:
1) 注册驱动(应用程序启动只做一次)
2) 建立连接(Connection)
3) 创建执行sql的语句(Statement, PreStatement)
4) 执行语句(增删改查)
5) 处理执行结果(ResultSet)
6) 释放资源
1. 注册驱动
从上面的介绍可以看出,程序要与任何数据库连接都要有相应的驱动程序。这个驱动程序需要注册到能被驱动程序管理器(DriverManager)找到。
DriverManager类包含一列Driver类,它们已通过调用方法DriverManager.registerDriver对自己进行了注册。所有Driver类都必须包含有一个静态部分。它创建该类的实例,然后在加载该实例时DriverManager类进行注册。这样,用户正常情况下将不会直接调用DriverManager.registerDriver;而是在加载驱动程序时由驱动程序自动调用。
有三种方式注册驱动,其中第一种是推荐的方式,另两种仅作了解:
1)最常用的方式(这将显式地加载驱动程序类。由于这与外部设置无关,因此推荐使用这种加载驱动程序的方法)
Class.forName(“com.mysql.jdbc.Driver”); // 以mysql驱动做示例。
2)直接创建对象
new com.mysql.jdbc.Driver();//创建driver对象,加载数据库驱动
String url="jdbc:mysql://localhost:3306/databasename";//数据库连接子协议
Connection conn=DriverManager.getConnection(url,"username","password");
不推荐理由:由new com.mysql.jdbc.Driver()可以知道,这里需要创建一个类的实例。创建类的实例就需要在java文件中将该类通过import导入,否则就会报错,即采用这种方式,程序在编译的时候不能脱离驱动类包,为程序切换到其他数据库带来麻烦
3) 设置系统属性
System.setProperty("jdbc.driver","com.mysql.jdbc.Driver");//系统属性指定数据库驱动
String url="jdbc:mysql://localhost:3306/databasename";//数据库连接子协议
Connection conn=DriverManager.getConnection(url,"username","password");
可以同时导入多个jdbc驱动,中间用冒号“:”分开,比如:
System.setProperty("jdbc.drivers","XXXDriver:XXXDriver:XXXDriver");
这样就一次注册了三个数据库驱动。
注:新加载的 Driver 类都要通过调用 DriverManager.registerDriver() 类进行自我注册,但实际使用中都不需要显式调用,因为这三种方式都采用自己的方式自动调用了这个注册函数。比如第二种方式:
com.mysql.jdbc.Driver类的静态代码快里面已经进行了修改的操作
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E)
{
throw new RuntimeException("Can't register driver!");
}
}
DriverManager是一个驱动管理器,内部有一个驱动注册表,map结构,可以向其注册多个驱动。
2. 建立连接
Connection 对象代表与数据库的连接。连接过程包括所执行的 SQL 语句和在该连接上所返回的结果。一个应用程序可与单个数据库有一个或多个连接,或者可与许多数据库有连接。打开连接与数据库建立连接的标准方法是调用DriverManager.getConnection方法。该方法接受含有某个 URL 的字符串。DriverManager 类(即所谓的 JDBC管理层)将尝试找到可与那个 URL 所代表的数据库进行连接的驱动程序。DriverManager 类存有已注册的 Driver 类的清单。当调用方法 getConnection 时,它将检查清单中的每个驱动程序,直到找到可与URL 中指定的数据库进行连接的驱动程序为止。Driver 的方法connect 使用这个 URL来建立实际的连接。
建立连接方法:
String url="jdbc:mysql://localhost:3306/databasename";//数据库连接子协议
Connection conn=DriverManager.getConnection(url,"username","password");
Jdbc url规范:
Jdbc 的url遵循一定的规范,jdbc:< 子协议 >:< 子名称 >
JDBC URL 的三个部分可分解如下:
(1)jdbc --协议。JDBC URL 中的协议总是 jdbc。
(2)<子协议> -- 驱动程序名或数据库连接机制(这种机制可由一个或多个驱动程序支持)的名称。子协议名的典型示例是 "odbc",该名称是为用于指定 ODBC 风格的数据资源名称的 URL 专门保留的。例如,为了通过JDBC-ODBC 桥来访问某个数据库,可以用如下所示的 URL:
jdbc:odbc:fred
本例中,子协议为 "odbc",子名称 "fred" 是本地ODBC 数据资源。
如果要用网络命名服务(这样 JDBC URL 中的数据库名称不必是实际名称),则命名服务可以作为子协议。例如,可用如下所示的 URL :jdbc:dcenaming:accounts-payable本例中,该 URL 指定了本地 DCE 命名服务应该将数据库名称 "accounts-payable" 解析为更为具体的可用于连接真实数据库的名称。
(3)<子名称> -- 一种标识数据库的方法。子名称可以依不同的子协议而变化。它还可以有子名称的子名称(含有驱动程序编程员所选的任何内部语法)。使用子名称的目的是为定位 数据库提供足够的信息。前例中,因为 ODBC 将提供其余部份的信息,因此用 "fred" 就已足够。然而,位于远程服务器上的数据库需要更多的信息。例如,如果数据库是通过Internet 来访问的,则在 JDBC URL 中应将网络地址作为子名称的一部份包括进去,且必须遵循如下所示的标准 URL 命名约定://主机名:端口/子协议假设 "dbnet" 是个用于将某个主机连接到 Internet 上的协议,则 JDBC URL 类似:
jdbc:dbnet://wombat:356/fred
特殊的"odbc" 子协议
子协议odbc 是一种特殊情况。它是为用于指定 ODBC 风格的数据资源名称的 URL 而保留的,并具有下列特性:允许在子名称(数据资源名称)后面指定任意多个属性值。odbc 子协议的完整语法为: jdbc:odbc:< 数据资源名称 >[;< 属性名 >=< 属性值 >]*
因此,以下都是合法的 jdbc:odbc 名称:
jdbc:odbc:qeor7jdbc:odbc:wombat
jdbc:odbc:wombat;CacheSize=20;ExtensionCase=LOWER
jdbc:odbc:qeora;UID=kgh;PWD=fooey
一些典型db的配置示例可以参考:
http://blog.csdn.net/ring0hx/article/details/6152528
注:oracle中连接和会话的概念,jdbc中的Connection对应oracle中的会话,而不是连接。
Oracle连接又分两种,从jdbc url可以看出配置的不同,一种是thin连接,一种是OCI,区别在性能和对集群的支持上,可以参考:
http://wyf289283641.iteye.com/blog/1911274
3.创建statement
Statement 对象用于将 SQL 语句发送到数据库中。实际上有三种 Statement 对象,它们都作为在给定连接上执行 SQL 语句的包容器:Statement、PreparedStatement(它从 Statement 继承而来)和 CallableStatement(它从 PreparedStatement 继承而来)。它们都专用于发送特定类型的 SQL 语句:
(1)Statement 对象用于执行不带参数的简单 SQL 语句;
(2)PreparedStatement 对象用于执行带或不带 IN 参数的预编译 SQL 语句;能有效防止sql注入和较好的执行效率。
注:所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作,其主要原因是程序没有细致地过滤用户输入的数据,致使非法数据侵入系统。可以通过使用PreparedStatement, 绑定变量等方式防止sql注入。具体相关内容需要查询专业书籍或其他资料。
(3)CallableStatement 对象用于执行对数据库有存储过程的调用。
下面分别是三种statement的创建方法:
1)Statement创建
Connection con = DriverManager.getConnection(url, "sunny", "");
Statement stmt = con.createStatement();
2)PreparedStatement创建
PreparedStatement 实例包含已编译的 SQL 语句。这就是使语句“准备好”。包含于 PreparedStatement 对象中的 SQL 语句可具有一个或多个 IN 参数。IN参数的值在 SQL 语句创建时未被指定。相反的,该语句为每个 IN 参数保留一个问号(“?”)作为占位符。每个问号的值必须在该语句执行之前,通过适当的setXXX 方法来提供。
由于 PreparedStatement 对象已预编译过,所以其执行速度要快于 Statement 对象。因此,多次执行的 SQL 语句经常创建为 PreparedStatement 对象,以提高效率。
PreparedStatement pstmt = con.prepareStatement("UPDATE table4 SET m = ? WHERE x = ?");
pstmt.setLong(1, 123456789); //1代表占位符的顺序,第一个占位符。
pstmt.setLong(2, 100000000);
3) CallableStatement ,这个用到的场景不多,本人没有用过。可以参考:
http://dev.yesky.com/SoftChannel/72342371961929728/20040917/1855399.shtml
4.处理结果
ResultSet 包含符合 SQL 语句中条件的所有行,并且它通过一套 get 方法(这些 get 方法可以访问当前行中的不同列)提供了对这些行中数据的访问。ResultSet.next 方法用于移动到 ResultSet 中的下一行,使下一行成为当前行。
java.sql.Statement stmt = conn.createStatement();
ResultSet r = stmt.executeQuery("SELECT a, b, c FROM Table1");
while (r.next())
{
// 打印当前行的值。
int i = r.getInt("a");
String s = r.getString("b");
float f = r.getFloat("c");
System.out.println("ROW = " + i + " " + s + " " + f);
}
ResultSet 维护指向其当前数据行的光标。每调用一次 next 方法,光标向下移动一行。最初它位于第一行之前,因此第一次调用 next 将把光标置于第一行上,使它成为当前行。随着每次调用 next 导致光标向下移动一行,按照从上至下的次序获取ResultSet 行。
在 ResultSet 对象或其父辈 Statement 对象关闭之前,光标一直保持有效。
在 SQL 中,结果表的光标是有名字的。如果数据库允许定位更新或定位删除,则需要将光标的名字作为参数提供给更新或删除命令。可通过调用方法getCursorName 获得光标名。
5.释放资源
数据库使用完毕需要释放资源,这些资源都是系统有限的宝贵资源,必须释放。释放jdbc资源的顺序RestltSet,Statement,Connection,基本是保证用完就关闭。其中Connection最重要,一定要关闭(线程池里连接的创建和关闭由池来管理,不需要程序员干预生命周期)。Connection关闭后ResultSet, Statement会自动关闭(但资源不会立即释放)。
Connection的使用原则是尽量晚创建,尽量早释放。
在关闭资源异常时,应该将资源赋null, 确保资源最大可能的被释放。(GC去回收)
6.处理事务
数据库的事务特性ACID,隔离级别这些本篇先不梳理了,后面梳理oracle时会单独整理。我们在使用时用的最多的是自动提交的设置。
Connection conn = DriverManager.getConnection();
conn.setAutocommit(false); // 关闭自动提交,这种是推荐的做法
//数据库操作
…
conn.commit(); //前面关闭了自动提交,这里就要自己控制提交或回滚(conn.rollback())
可以参考:
http://blog.csdn.net/chenyongsuda/article/details/5641412
事务还可分为本地事务和分布式事务,可以参考:
http://jackyin5918.iteye.com/blog/1922042
三、DataSource和JNDI(Java Naming and Directory)
1.从上面的内容可以看出,如果要与数据库交互必须要获取数据库连接,上面是通过DriverManager.getConnection("url")获取的,需要把url传进去硬编码。DataSource是sun提供的替代DriverManager的方法,类全名是javax.sql.DataSource。javadoc描述的挺清楚:
* A factory for connections to the physical data source that this
* DataSource object represents. An alternative to the
* DriverManager facility, a DataSource object
* is the preferred means of getting a connection. An object that implements
* the DataSource interface will typically be
* registered with a naming service based on the
* Java Naming and Directory (JNDI) API.
通过DataSource获取Connection比DriverManager更灵活,它可以结合JNDI在配置文件里配置数据库的url,当数据库属性改变时不需要修改代码,只要修改配置文件就可以了。另一个优点就是对数据库连接池的支持了。比如spring的JdbcTemplate就是用DataSource来获取连接。
2.JNDI(Java Naming and Directory Interface)是SUN公司提供的一种标准的Java命名系统接口,JNDI提供统一的客户端API,通过不同的访问提供者接口JNDI SPI的实现,由管理者将JNDI API映射为特定的命名服务和目录系统,使得Java应用程序可以和这些命名服务和目录服务之间进行交互。集群JNDI实现了高可靠性JNDI[8],通过服务器的集群,保证了JNDI的负载平衡和错误恢复。在全局共享的方式下,集群中的一个应用服务器保证本地JNDI树的独立性,并拥有全局的JNDI树。每个应用服务器在把部署的服务对象绑定到自己本地的JNDI树的同时,还绑定到一个共享的全局JNDI树,实现全局JNDI和自身JNDI的联系。
JNDI里最常用的类就是InitialContext(javax.naming.InitialContext).
这样的描述仍然不能理解它的作用,只能通过使用去理解,其实所有的程序都是这样,实践,实践,实践。
3.DataSource和JNDI结合的例子
在Spring框架中有如下3种获得DataSource对象的方法:
1)从JNDI获得DataSource.
2)从第三方的连接池获得DataSource.
3)使用DriverManagerDataSource获得DataSource.
下面分别给出示例:
1)从JNDI获得DataSource.
step1、Spring引用JNDI数据源配置信息:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jcptDataSourceJNDI</value>
</property>
</bean>
jcptDataSourceJNDI是tomcat或者其他应用服务器配置的JNDI.
step2、关于JNDI的配置(tomcat):
修改tomcat目录conf/context.xml文件:
<Resource name="jcptDataSourceJNDI" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10" username="tysp"
password="12345678" driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@192.168.1.35:1521:orcl"/>
step3、通过JNDI获取DataSource:
Context context = new InitialContext();
DataSource ds = (DataSource)context.lookup("java:comp/env/jcptDataSourceJNDI");
2)使用DBCP连接池获取
要在Spring中使用DBCP连接池,需要引入commons-collections.jar、commons-dbcp.jar和commons-pool.jar。
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@192.168.1.35:1521:orcl" />
<property name="username" value="or_meal"></property>
<property name="password" value="or_meal"></property>
<property name="maxActive" value="100"></property>
<property name="maxIdle" value="30"></property>
<property name="maxWait" value="10"></property>
<property name="defaultAutoCommit" value="false"></property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect
</prop>
<prop key="show_sql">true</prop>
<prop key="format_sql">true</prop>
</props>
</property>
<property name="mappingResources">
<list></list>
</property>
</bean>
3)使用DriverManagerDataSource
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>oracle.jdbc.driver.OracleDriver</value>
</property>
<property name="url">
<value>jdbc:oracle:thin:@192.168.1.35:orcl</value>
</property>
<property name="username">
<value>or_meal</value>
</property>
<property name="password">
<value>or_meal</value>
</property>
</bean>
在实际项目中可以选择合适的配置方式。以上三种配置的不同可以参考:
http://blog.csdn.net/junjun16818/article/details/6945598
另外还可以参考资料:
http://blog.csdn.net/jingliangfu/article/details/6036730
http://cyf-123456.iteye.com/blog/408012
发表评论
-
slf4j 的MDC (附带主动获取方法堆栈)
2015-08-03 17:29 54001. 主动获取方法调用链 ... -
<java 序列化&反序列化> serialVersionUID的作用(转)
2015-02-11 18:12 1213参考: http://www.strutshome.com/i ... -
Class(ClassLoader)#getResource, getResourceAsStream
2014-10-31 17:04 2376一、Class#getResourceAsStream 1.1 ... -
自定义注解
2014-10-15 16:17 22451.Annotation(注解)介绍 Annotation(注 ... -
MD5 几种方法的选择
2014-03-07 12:13 6462md5加密实现方法有很多种,也导致很难选择。大概分析下自己了解 ... -
静态变量初始化 && 类实例初始化
2014-02-12 15:45 3669【本文整合多篇网文+验证扩展而成】 1. 静态变量(块)初始 ... -
<时间-2>Date & DateFormat & SimpleDateFormat & Calendar
2014-02-07 12:57 4057前面介绍了计算机世界 ... -
<时间-1>计算机世界中的时间概念
2014-01-22 22:59 3487在计算机中表示时间是 ... -
枚举原理及使用
2014-01-04 13:14 1468参考:《java入门经典》 ... -
泛型编程
2014-01-04 10:47 2029参考资料:《java核心技术 卷1》 网络 Java中的泛型 ... -
我的烂笔头 -- java常识、常见问题
2013-08-23 12:15 16241.Integer.MAX_VALUE Integer ...
相关推荐
<artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- MySQL Connector --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.23</...
附录<br>附录A SQL入门<br>什么是SQL<br>什么是数据库<br>关系数据库基础<br>关系数据库的优点和缺点<br>SQL:数据定义<br>基本数据操作<br>数据完整性<br>表达式<br>连接<br>合并<br>子查询<br>小结<br>附录B 序列...
1 应用Struts的网站建设 <br><br> <br> <br>Java基础<br> 1 20个Java基础Tips <br> 2 abstract,static,final修饰符 <br> 3 ChinaUnix.net Java精华贴 <br> 4 ANT学习笔记 <br> 5 极度性能调整 <br><br> <br>FAQs<br>...
<br>1、servlet与JSP技术概述<br>2、servlet基础<br>3、客户请求的处理:表单数据<br>4、客户请求的处理:HTTP请求报头<br>5、服务器响应的生成:HTTP状态代码<br>6、服务器响应的生成: HTTP响应报头<br>7、cookie...
第1章 Java系统环境概述<br>第2章 Java语言基础<br>第3章 程序流程控制<br>第4章 类与对象<br>第5章 消息、继承与多态<br>第6章 数组<br>第7章 字符串类<br>第8章 文字与图形GUI设计<br>第9章 常用组件GUI设计<br>第...
前言<br>第一部分 JSP入门<br>第1章 概述 <br>1.1 Java技术 <br>1.1.1 Java技术的发展 <br>1.1.2 JavaBeans <br>1.1.3 JDBC <br>1.1.4 J2EE <br>1.1.5 EJB <br>1.1.6 Java Servlet <br>1.2 JSP技术 <br>1.2.1 JSP...
<br>1、servlet与JSP技术概述<br>2、servlet基础<br>3、客户请求的处理:表单数据<br>4、客户请求的处理:HTTP请求报头<br>5、服务器响应的生成:HTTP状态代码<br>6、服务器响应的生成: HTTP响应报头<br>7、cookie...
<br>1、servlet与JSP技术概述<br>2、servlet基础<br>3、客户请求的处理:表单数据<br>4、客户请求的处理:HTTP请求报头<br>5、服务器响应的生成:HTTP状态代码<br>6、服务器响应的生成: HTTP响应报头<br>7、cookie...
目录<br><br>前言<br>1. 一般信息<br>1.1. 关于本手册<br>1.2. 本手册采用的惯例<br>1.3. MySQL AB概述<br>1.4. MySQL数据库管理系统概述<br>1.4.1. MySQL的历史<br>1.4.2. MySQL的的主要特性<br>1.4.3. MySQL稳定性...
<artifactId>spring-jdbc</artifactId> <version>${spring-version}</version> </dependency> <!-- Spring Web --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</...
- 添加`<Context>`元素来指定DBTest应用的上下文路径和文档基础目录: ```xml <Context path="/DBTest" docBase="DBTest" debug="5" reloadable="true" crossContext="true"> </Context> ``` 2. **配置...
Spring容器高级主题<br>第6章 Spring AOP基础<br>第7章 基于@AspectJ和Schema的<br>第7章 AOP<br>第3篇 数据库访问<br>第8章 Spring对DAO的支持<br>第9章 Spring的事务管理<br>第10章 使用Spring JDBC访问数据库<br>...
在了解Java Servlet连接MySQL数据库的过程中,我们将会涉及多个相关知识点,包括Java Servlet的基本概念、MySQL数据库基础、JDBC的使用,以及如何在Tomcat服务器上配置Servlet来连接MySQL数据库。 首先,Java ...
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/testdb</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password...
1. **`<Context>`** 标签定义了一个Web应用程序的上下文环境。其中: - `path` 属性指定了该Web应用部署的路径。 - `reloadable` 属性表示是否允许热加载,即在不重启应用的情况下重新加载修改过的类。 - `...
jdbc:mysql://<hostname>:<port>/<database>?<parameters> ``` 其中,`<hostname>`是数据库服务器地址,`<port>`是MySQL服务监听的端口,默认为3306,`<database>`是数据库名,`<parameters>`可以包含如useSSL=...
- **URL格式**:jdbc:sybase:Tds:<host>:<port2048>/<database> 或 jdbc:jtds:<server_type>://<host>[:<port>][/<database>] - **安装信息**:加载对应jar文件到驱动管理器。 5. **Informix IDS JDBC驱动** - *...
<transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mydb?useSSL=false&...