JdbcUtils工具类:封装加载驱动,获取连接,释放资源
RowMapper工具类:封装处理结果集
JdbcTemplate工具类:封装查询一条多条结果,和增删改冗余,操作减少dao层代码冗余
将Class.forName(“com.mysql.jdbc.Driver”);代码放到static静态代码块中,因为static静态代码块只有第一次类加载的时候执行一次就不再执行了,只需要加载一次,不需要重复加载(减少浪费资源)。
properties配置文件:
作用:封装加载驱动,获取连接,释放资源等常用变量,避免将代码写死,提高代码复用性
创建方法:先在src下创建一个com.conf配置文件包,再new一个file文件命名以properties结尾,将会变的参数以键值对的形式存到properties文件中
使用方法:
①.将properties文件读入流中,使用类名.class获取字节码文件,字节码文件.getResourceAsStream(“文件路径”)来获取文件的流,返回一个输入流。
InputStream is = JdbcUtils2.class.getResourceAsStream("/com/conf/db.properties");
②.创建一个全局的静态properties对象,将读过来的properties文件流使用load(is)方法加载到properties对象中
为什么是静态的:因为加载驱动是放在static静态代码块中,只有静态的才能在静态代码块中使用。
③.Properties里面已经以键值对的形式存放db.properties对象了,可以通过properties.getProperty(“键”)来读取值了
④.关闭inputStream输入流
1.什么是事物: 逻辑上的一组操作,组成这组操作的逻辑单元要么一起成功,要么一起失败。
例:银行转账,自己账户扣钱,对方账户加钱
2.事物的特性
①.原子性:强调事务的不可分割.(要么都做,要么都不做)
②.一致性:强调的是事务的执行的前后,数据的完整性要保持一致.
③.隔离性:一个事务的执行不应该受到其他事务的干扰.
④.持久性(永久性):事务一旦结束(提交/回滚)数据就持久保持到了数据库.
3.MySql的TCL(事物控制语言)
默认是自动提交
1.set autocommit=false,设置为手动提交
2.rollback,回滚
3.commit,提交
4.jdbc的TCL(事物控制语言)
1.默认事务自动提交策略:一条命令自成一个完整事务
①.可以一条sql就是一个事务
②.也可以将多条sql组合成一个事务,这组sql要么同时执行成功,要么都失败
2.需求:各个逻辑单元要么一起成功,要么一起失败(比如转账)
3.手动控制事务的API
①.conn.setAutoCommit (false);将jdbc的事务提交改为手动提交
②.conn.commit();提交
③.conn.rollback();回滚
注意:连接提交策略一经设置,永久改变
ThreadLocal使用
1.使用事务控制完成业务功能
2.目的:写项目要分层,为了不造成资源浪费(类与类相互调用,都需要连接数据库,但是它们属于同一个线程,在一个线程的各段代码中,只使用一个连接conn就可以了)
3.功能:为同一个线程保存同一个连接值,为不同线程保存不同的连接值
4.创建对象: ThreadLocal<t>
tdl = new ThreadLocal<t >
;泛型里面可以放任何东西,字符串,连接
5.方法:
①.set(T t) ;//将t对象添加至当前线程
②.get() ;//获得当前线程中的对象
③.remove () ;//移除当前线程中的对象
1.创建:
创建多个dbcp.properties文件,存储多个不同的连接池
2.作用:
使用连接池技术,避免重复创建和销毁连接资源,减少系统开销。
3.连接池的工作原理:
①使用连接池前:用jdbc连接数据库时,先getConnection获取连接,用完后要release释放连接,再次连接重复前两步,对程序性能影响很大。
②使用连接池后:在程序开始之前,先创建几个连接,将连接放入到连接池中,连接池中缓存了一定量的Connection对象,当用户需要使用连接时,从连接池中获取,使用完毕之后将连接还回连接池。
4.连接池的种类:
DBCP连接池,C3P0,Tmcat内置连接池等
5.使用步骤:
1.单独使用DBCP需要导入三个dbcp相关jar包,Add to Bulid Path依赖到项目中
①.commons-dbcp-1.4.jar
②.commons-collections-3.2.1.jar
③.commons-pool-1.5.4jar
2.导入dbcp的配置文件dbcp.properties,也可以自己编写(相当于之前自己编写的db.properties)
driverclassName=com.mysql.jbcp.Driver
url=jdbc:mysql://localhost:3306/mybase1?useUnicode=true&characterEncoding=utf-8
user=root
password=root123
initialSize=10 //初始连接数量
maxActive=50 //最大活跃连接数量
maxIdle=20 //最大空间连接数
minIdle=5 //最小空间连接数
maxWait=60000 //最大等待时间ms(毫秒),从连接池获取连接,如果连接池空了,等待的最大时间
connectionProperties=useUnicode=true;characterEncoding=utf-8
defaultAutoCommit=true
defaultTransactionIsolation=READ_COMMITTED,默认事务隔离:读已提交?
3.API开发,从连接池获得连接
声明连接池:static DataSource pool=null;
创建连接池:pool=BasicDataSourceFactory.createDataSource(pro);
从连接池里面来获取连接:conn=pool.getConnection();(不需要使用DriverManager.getConnection创建连接了)
package com.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class JdbcUtils {
//加载驱动
static{
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//获取连接(自己决定,封装到方法中)
//static静态,直接使用类名.方法名更方便
public static Connection getconnection() throws Exception{
String url="jdbc:mysql://localhost:3306/mybase?userUnicode=true&characterEncoding=utf8";
String user="root";
String password="root123";
Connection conn=DriverManager.getConnection(url,user,password);
return conn;
}
//释放资源
public static void release(ResultSet rs,PreparedStatement pstm,Connection conn) throws Exception{
if(rs!=null){
rs.close();
}
if(pstm!=null){
pstm.close();
}
if(conn!=null){
conn.close();
}
}
}
package com.jdbc;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import com.util.JdbcUtils;
public class testJdbcUtils1 {
public static void main(String[] args) throws Exception {
Connection conn = JdbcUtils.getconnection();
String sql="update emp set job=? where ename=?";
PreparedStatement pstm = conn.prepareStatement(sql);
pstm.setString(1, "clerk");
pstm.setString(2, "夏雪儿");
pstm.executeUpdate();
JdbcUtils.release( null,pstm, conn);
System.out.println(conn);
}
}
driverClassName=com.mysql.jdbc.Driver
url=jdbc\:mysql\://localhost\:3306/mybase1
username=root
password=root123
package com.util;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
public class JdbcUtils2 {
static InputStream is =null;
static Properties properties=new Properties();
static{
try {
is= JdbcUtils2.class.getResourceAsStream("/com/conf/db.properties");
try {
//将流加载到文件中
properties.load(is);
} catch (Exception e) {
e.printStackTrace();
}
Class.forName(properties.getProperty("driverClassName"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//获取连接(自己决定,封装到方法中)
//static静态,直接使用类名.方法名更方便
public static Connection getconnection() throws Exception{
String url=properties.getProperty("url");
String user=properties.getProperty("username");
String password=properties.getProperty("password");
Connection conn=DriverManager.getConnection(url,user,password);
return conn;
}
//释放资源
public static void release(ResultSet rs,PreparedStatement pstm,Connection conn) throws Exception{
if(rs!=null){
rs.close();
}
if(pstm!=null){
pstm.close();
}
if(conn!=null){
conn.close();
}
}
}
package com.jdbc;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import com.util.JdbcUtils2;
public class testJdbcUtils2 {
public static void main(String[] args) throws Exception {
Connection conn = JdbcUtils2.getconnection();
String sql="update emp set job=? where ename=?";
PreparedStatement pstm = conn.prepareStatement(sql);
pstm.setString(1, "manager");
pstm.setString(2, "夏雪儿");
pstm.executeUpdate();
JdbcUtils2.release( null,pstm, conn);
System.out.println(conn);
}
}
set autocommit=false;
insert into dept(deptno,dname,loc) values(50,'后勤部','郑州');
rollback;
commit;
package com.jdbc;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.util.JdbcUtils2;
public class TestTrascation {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement pstm1=null;
PreparedStatement pstm2=null;
try {
//加载驱动获取连接
conn = JdbcUtils2.getconnection();
//设置jdbc事务手动提交
conn.setAutoCommit(false);
//事务1:降职,事务2:降薪
//分析:若白展堂从经理变成了小职员,他的奖金也要减少
String sql1="update emp set job='clerk' where ename='白展堂'";
pstm1=conn.prepareStatement(sql1);
pstm1.executeUpdate();
//comm=4000不符合comm的数据类型,不大于3位数,所以异常回滚
//String sql2="update emp set comm=4000 where ename='白展堂'";
String sql2="update emp set comm=100 where ename='白展堂'";
pstm2=conn.prepareStatement(sql2);
pstm2.executeUpdate();
//提交事务:如果事务1和2都成功执行了就提交事务
//否则捕捉异常,在catch里面执行事务回滚
conn.commit();
} catch (Exception e) {
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally{
try {
JdbcUtils2.release(null, pstm2, conn);
JdbcUtils2.release(null, pstm1, conn);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
主要改变:获取连接,同一个线程获得相同连接
package com.util;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
public class JdbcUtils3 {
static InputStream is =null;
static Properties properties=new Properties();
static ThreadLocal<Connection> tdl=new ThreadLocal<Connection>();
static{
try {
is= JdbcUtils2.class.getResourceAsStream("/com/conf/db.properties");
try {
//将流加载到文件中
properties.load(is);
} catch (Exception e) {
e.printStackTrace();
}
Class.forName(properties.getProperty("driverClassName"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//获取连接(自己决定,封装到方法中)
//static静态,直接使用类名.方法名更方便
public static Connection getconnection() throws Exception{
//现获取当前线程中所拥有的连接
Connection conn = tdl.get();
//如果没有就创建一个
if(conn==null){
String url=properties.getProperty("url");
String user=properties.getProperty("username");
String password=properties.getProperty("password");
conn=DriverManager.getConnection(url,user,password);
//将创建的线程写入到当前线程中
tdl.set(conn);
}
//如果有就直接返回当前线程拥有的连接,让同一个线程能使用同一个连接
return conn;
}
//释放资源
public static void release(ResultSet rs,PreparedStatement pstm,Connection conn) throws Exception{
if(rs!=null){
rs.close();
}
if(pstm!=null){
pstm.close();
}
if(conn!=null){
//关闭连接
conn.close();
//同时将连接从当前线程中移除
tdl.remove();
}
}
}
package com.jdbc;
import java.sql.Connection;
import com.util.JdbcUtils3;
public class TestThreadLocal2 {
public static void main(String[] args) throws Exception {
Connection conn1 = JdbcUtils3.getconnection();
Connection conn2 = JdbcUtils3.getconnection();
System.out.println("conn1:"+conn1);
System.out.println("conn2:"+conn2);
Thread t1=new Thread(){
public void run(){
try {
Connection conn3 = JdbcUtils3.getconnection();
System.out.println("conn3:"+conn3);
} catch (Exception e) {
e.printStackTrace();
}
}
};
t1.start();
}
}
conn1:com.mysql.jdbc.JDBC4Connection@64cf5b3
conn2:com.mysql.jdbc.JDBC4Connection@64cf5b3
conn3:com.mysql.jdbc.JDBC4Connection@6c977c1f
driverClassName=com.mysql.jdbc.Driver
url=jdbc\:mysql\://localhost\:3306/mybase1
username=root
password=root123
package com.util;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
public class JDBCUtils {
static InputStream is =null;
//配置文件的操作类Properties类(java.util.Properties)
static Properties properties=new Properties();
static DataSource pool=null;
//会话:登录系统后,可以进行多个操作,但只登录了一次
//事务:每个操作,如第一次转账和第二次转账是两个事务
//线程:一个人操作和多个人操作的问题
//一个会话可以创建多个事务,一个事务只能由一个会话产生
//一个事务可以产生多个线程,一个线程同一时间内只能由一个事务执行
//创建事务,类之间互调属于同一个线程,为同一个线程保存同一个连接值conn,为不同线程保存不同的连接值
//泛型里面可以放任意对象,用事务保存什么就放什么类型
static ThreadLocal<Connection> tdl=new ThreadLocal<Connection>();
//创建连接池,并将dbcp.properties以键值对的形式读入
static{
//这个try是为createDataSource捕获的异常
try {
//JDBCUtils.class为JDBCUtils的字节码文件
//当前class的包路径为基准,获取dbcp.properties文件的流
is = JDBCUtils.class.getResourceAsStream("/com/conf/dbcp.properties");
//从输入流中以键值对的形式读取dbcp.propertie,要捕捉异常
try {
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
}
//使用BasicDataSourceFactory数据连接池工厂类创建一个连接池
//并将从dbcp.propertie读取出的键值对放入连接池中
pool = BasicDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
//关闭流文件,捕获异常
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//获取连接
public static Connection getConnection() throws Exception{
//获取当前线程中拥有的连接,如果没有就创建一个
Connection conn = tdl.get();
if(conn==null){
//从字节流中取值
//String url = properties.getProperty("url");
//String username = properties.getProperty("username");
//String password = properties.getProperty("password");
//获取连接,抛出Exception异常
//conn=DriverManager.getConnection(url, username, password);
//从连接池中取值,并将连接加入当前线程中
conn=pool.getConnection();
tdl.set(conn);
}
return conn;
}
//释放资源
//导包导的都是有关sql的包
public static void release(ResultSet rs,PreparedStatement pstm,Connection conn) throws Exception{
if(rs!=null){
rs.close();
}
if(pstm!=null){
pstm.close();
}
//关闭连接,同时将连接从当前线程中移除
if(conn!=null){
conn.close();
tdl.remove();
}
}
}
package com.jdbc;
import java.sql.Connection;
import com.util.JDBCUtils;
public class testJDBCUtils {
public static void main(String[] args) throws Exception {
//由于有static关键字修饰,可以直接使用类名.方法名调用getConnection()方法获取连接
Connection conn1 = JDBCUtils.getConnection();
Connection conn2 = JDBCUtils.getConnection();
//同一线程,获得的是同一个连接对象
System.out.println("conn1:"+conn1);
System.out.println("conn2:"+conn2);
//那在创建一个新的线程并将其开启,事务为不同线程保存的就不是同一个连接对象了
Thread t1=new Thread(){
public void run(){
try {
Connection conn3 = JDBCUtils.getConnection();
System.out.println("conn3:"+conn3);
} catch (Exception e) {
e.printStackTrace();
}
}
};
t1.start();
}
}
conn1:jdbc:mysql://localhost:3306/mybase, UserName=root@localhost, MySQL Connector Java
conn2:jdbc:mysql://localhost:3306/mybase, UserName=root@localhost, MySQL Connector Java
conn3:jdbc:mysql://localhost:3306/mybase, UserName=root@localhost, MySQL Connector Java