jdbc复习笔记。
准备
commons-dbcp-1.4-bin.zip
commons-dbcp-1.4-src.zip
commons-pool-1.5.6.jar
c3p0-0.9.1.2.jar
c3p0-0.9.1.2.src.zip
持久化和JDBC概述
持久化
持久化(persistence),把数据保存到可掉电式存储设备中以供之后使用。
大多数情况下,特别是企业级应用,数据持久化意味着将内存中的数据保存到硬盘中加以“固化”,而持久化的实现过程大多通过各种关系型数据库来完成。
持久化的主要应用是将内存中的数据存储在关系型数据库中,当然也可以存储在磁盘文件、XML数据文件中。
在Java中,数据库存取技术只能通过JDBC访问数据库:
JDBC访问数据库的形式主要有两种:
1).直接使用JDBC的API去访问数据库服务器(MySQL/Oracle)。
2).间接使用JDBC的API去访问数据库服务器。
第三方O/R Mapping工具,如Hibernate,Mybatis等(底层依然是JDBC)。
JDBC是java访问数据库的基石,其他技术都是对JDBC的封装。
JDBC
JDBC是一种用于执行SQL语句的java API,可以为多种关系型数据库提供统一访问,它由一组用java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。
JDBC为访问不同的数据库提供了一种统一的途径,为开发者屏蔽了一些细节问题。JDBC的目标是使java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员无需对特定的数据库系统有过多了解,加快开发过程。
java.sql包装是JDBC的API。
在开发中使用到的关于JDBC的类/接口全部引入的是java.sql/javax.sql包中的,不要使用各大数据库提供的API。
获取JDBC的连接对象
1.加载注册驱动
Class.forName(“驱动实现类的全限定名”);
MySQL:Class.forName(“com.mysql.jdbc.Driver”);
为啥写上这一句话,就会把驱动进行加载注册?
步骤1:把com.mysql.jdbc.Driver这份字节码加载进JVM—->创建Class对象。
步骤2:当一份字节码被加载进JVM,就会执行字节码中的静态代码块。
见com.mysql.jdbc.Driver源码
|
|
步骤3:静态代码块中,就是使用DriverManager.registerDriver(new Driver())注册驱动的。
2.使用DriverManager获取连接
Connection conn=DriverManager.getConnection(String url,String user,String password);
跟据官方API,从JDBC4.0(jdk1.6)开始,数据库连接驱动包里必须包含注册驱动那句话,所以省略它不会报错。建议仍然手动注册,兼容java5。
常用接口
Connection接口
表示JDBC的连接对象。
Statement接口
用于执行静态SQL(写死的SQL)语句。
常用方法:
int executeUpdate(String sql)
ResultSet executeQuery(String sql)
close()
PreparedStatement和Statement区别
PreparedStatement比Statement优势:
1.代码可读性/维护性更高。
2.PreparedStatement是预编译语句对象,PreparedStatement的执行性能更高。
3.安全性更高,防止SQL注入问题。
ResultSet接口
表示查询的结果集(查询结果的封装对象),是通过执行查询语句得到的。
常用方法:
boolean next()
Xxx getXxx(int columnIndex) : 获取当前行的第几列的数据,从1开始(不建议)。
Xxx getXxx(String columnName) : 获取当前行的执行列名对应列的数据,可以使用别名,注意:Xxx是数据类型,比如String,long,int,boolean等。
Object getObject(int/String columnIndex) : 获取某一列的数据,统统使用Object来接收。
close()
ResultSet对象具有指向其当前数据行的光标。
最初,光标被置于第一行之前,next方法将光标移动到下一行。
因为该方法在ResultSet对象没有下一行时返回false,所以可以在while循环中使用它来迭代结果集。
从ResultSet中取出数据,实质上是取出当前指针指向的当前行的数据。
其实,在表中,一行数据就是一个对象。可以使用一个对象来封装表中的一行数据。比如:使用Product对象,可以封装一行商品数据。若要封装多行,可以使用List
JDBC事务的细节
1.在JDBC中事务是默认自动提交的。在执行DML语句的时候就已经提交事务了。
2.事务只对DML语句有效,对于DDL(查询)没效果,查询不会涉及到修改数据库。
3.回滚事务在释放资源,释放锁机制。(InnoDB:行锁;MyISAM:表锁)
4.在Mysql中,MyISAM不支持外键,不支持事务;InnoDB都支持。
在Spring中有专门的事务管理器(TransactionManager)。
批量操作(batch)
当需要成批插入或者更新记录时,可以采用java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率。
JDBC的批量处理语句包括下面两个方法:
addBatch(String) – 添加需要处理的SQL语句或是参数。
executeBatch() – 执行批量处理语句。
通常我们会遇到两种批量执行SQL语句的情况:
多条SQL语句的批量处理。Statement
一个SQL语句的批量传参。PreparedStatement
Mysql不支持PreparedStatement的性能优化,也不支持批量操作性能优化。
Statement:
Statement批处理,一次性可以执行多条sql语句,需要编译多次。
应用场景:系统初始化(创建表,创建数据等)。
批量处理sql语句, int[] st.executeBatch()
清除缓存, st.clearBatch()
PreparedStatement:
PreparedStatement批处理,执行一条sql语句,编译一次,执行sql语句的参数不同。
应用场景:表数据初始化。
添加批量参数, ps.addBatch() —添加实际参数,执行之前,需要执行 ps.setXxx()设置实际参数执行批处理, int[] ps.executeBatch()
清除缓存: ps.clearBatch()
清除参数: ps.clearParameter()
大数据类型(BLOB和TEXT)
BLOB
TINYBLOB,BLOB,MEDIUMBLOB,LONGBLOB都是二进制类型,唯一的不同就是容量不同。
可以把二进制的数据保存到数据库,比如可以把一个音频,视频,图片存到数据库中。
注意:在开发中往往把二进制文件的保存路径存储到数据库中,而不是把数据存储到数据库。
TEXT
用于保存文字比较多(博客/小说)。
TINYTEXT,TEXT,MEDIUMTEXT,LONGTEXT,对应着java中的String,在java代码中没有变化。
获取自动生成的主键
Statement:
int executeUpdate(String sql): 执行DML/SQL语句
int executeUpdate(String sql,int autoGeneratedKeys):
参数: autoGeneratedKeys:是否需要返回自动生成的主键
Statement.RETURN_GENERATED_KEYS:要返回
Statement.NO_GENERATED_KEYS:不返回
ResultSet getGeneratedKeys() :获取自动生成的主键
PreparedStatement:
conn.prepareStatement(String sql,int autoGeneratedKeys);
ResultSet getGeneratedKeys() :获取自动生成的主键
连接池
目的:重复利用Connection资源。
概述
在java中,使用javax.sql.DataSource来表示连接池对象。
DataSource:数据源,其实就是连接池,Connection Pool。
为什么必须使用数据库连接池:
普通的JDBC数据库连接使用DriverManager来获取,每次向数据库建立连接的时候都要将Connection加载到内存中,再验证用户名和密码。需要数据库连接的时候,就向数据库要求一个,执行完成后再断开连接,这样的方式将会消耗大量的资源和时间,数据库的连接资源并没有得到很好的重复利用,若同时有几百人甚至几千人在线,频繁的进行数据库连接操作将占用很多的系统资源,严重的甚至会造成服务器的崩溃。
对于每一次数据库连接,使用完后都得断开,否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄露,最终将导致重启数据库。
这种开发不能控制被创建的连接对象数,系统资源会被毫无顾忌的分配出去,如连接过多,也可能导致内存泄露,服务器崩溃。
连接池的技术比较多,SUN公司仅仅是提供了DataSource的接口,不提供任何实现。由各大服务器厂商提供DataSource的实现(Tomcat,WebLogic)。
属性
eg:
初始化连接数=5
设置事先先在连接池存储个5个Connection对象。
设置最大连接数=10
设置在连接池中最多有10个Connection对象。
最小连接数=2
设置在连接池中最少有两个Connection对象。
超时时间=5min
设置一个客户如果5分钟没有动作,则会被自动释放。
客户的最大等待时间=2min
设置客户最多有两分钟时间去获取Connection对象,若超过2分钟,还没获取到,则系统提示,稍后再试…
使用连接池和不使用连接池在代码上的区别
不使用连接池:使用DriverManager来获取Connection对象。
Connection conn=DriverManager.getConnection(url,username,password);
使用连接池:直接找连接池(DataSource对象),取出Connection即可。
在创建DataSource对象时,设置连接数据库的url,user,password。
Connection conn=DataSource对象.getConnection();
接下来的代码和以前相同。
释放连接:
代码:Connection对象.close();
不使用连接池:直接和数据库服务器建立连接关系,而断开也是和数据库服务器断开连接。
使用连接池:直接和连接池建立连接关系,而断开也是把Connection对象还给连接池,供其他客户使用。没有真正的和数据库断开。如此一来,一个Connection对象就得到了充分的利用。
常见的连接池技术
dbcp:Spring推荐的连接池技术
c3p0:Hibernate推荐的连接池技术
dbcp
准备:
1.拷贝jar包。commons-dbcp-1.4.jar,commons-pool-1.5.6.jar。
2.阅读文档。解压commons-dbcp-1.4-src.zip,查看commons-dbcp-1.4-src -> doc -> BasicDataSourceExample.java,里面有连接池的使用案例。
步骤:
1.创建DataSource对象。
2.从DataSource对象中获取Connection对象。
3.接下来使用Connection就和以前相同。
注意:dbcp.properties中的key必须是BasicDataSource对象里的属性(setter)。否则无法把对应的配置信息,设置到DBCP连接池中。
dbcp.properties:
driverClassName=
url=
username=
password=
initialSize=
//连接池的最大值
maxActive=
//连接池的最大空闲数
maxIdle=
c3p0
准备:
1.拷贝jar包。c3p0-0.9.1.2.jar。
2.阅读文档。解压c3p0-0.9.1.2.src.zip,查看c3p0-0.9.1.2.src -> src -> doc -> index.html -> Quickstart,里面有连接池的使用案例。
步骤:
1.创建DataSource对象。
2.从DataSource对象中获取Connection对象。
3.接下来使用Connection就和以前相同。
注意:
1.文件名称必须叫作c3p0.properties。
2.c3p0.properties必须放在CLASSPATH的根路径下。
3.c3p0.properties文件中的key必须以”c3p0.”作为前缀。
4.c3p0.properties文件中的key必须是ComboPooledDataSource类的属性名。