Java学习-JDBC

JAVA——JDBC学习 JAVA中的JDBC、JDBC概述、原理、使用步骤、Drudi、baseDao 阅读详情

一、概述

1.概念:JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API。

2.作用: JDBC是Java访问数据库的标准规范,可以为不同的关系型数据库提供统一访问,它由一组用Java语言编写的接口(大部分)和类组成。

3.JDBC和驱动的关系:
Java提供访问数据库规范称为JDBC,而生产厂商提供规范的实现类称为驱动。
在这里插入图片描述
4.JDBC规范(四个核心):

  • DriverManager:驱动管理类;
  • Connection:与数据库创建连接的接口,实现类在驱动中;
  • Statement:操作数据库SQL语句的接口,实现类在驱动中;
  • ResultSet:结果接口,实现类在驱动中;

二、JDBC的入门

1.导入驱动jar包
位置:创建lib目录,用于存放当前项目需要的所有jar包;
导包:右键project->property->java build path->libaries->add external jars;
在这里插入图片描述
2.原生开发步骤
1) 注册驱动
2) 获得连接
3) 获得执行sql语句的对象
4) 执行sql语句,并返回结果
5) 处理结果集
6) 释放资源

public static void main(String[] args) throws ClassNotFoundException, SQLException {
		//注册驱动
		Class.forName("com.mysql.jdbc.Driver");
		//获取与数据库连接对象
		String url = "jdbc:mysql://localhost:3306/db1216";
		java.sql.Connection ct = DriverManager.getConnection(url, "root", "root");
		//获取SQL语句执行对象
		Statement st = ct.createStatement();
		//执行SQL语句
		ResultSet exe = st.executeQuery("select * from person");
		//处理结果集
		while(exe.next()) {
			int pid = exe.getInt("pid");
			String pname = exe.getString("pname");
			int page = exe.getInt("page");
			String psex = exe.getString("psex");
			String format = "%d %s %d %s%n";
			System.out.printf(format, pid,pname,page,psex);
		
		}
		//释放资源
		exe.close();
		st.close();
		ct.close();
	}
	console结果:
	1 小明 18 男
	2 小华 20 男
	3 小红 18 女
	4 小芳 23 女
	5 小亮 17 男

3.工具类 JDBCUtils的编写
示例:

//工具类
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;

public class JDBCUtils {
	private static String drivername = "com.mysql.jdbc.Driver";
	private static String url = "jdbc:mysql://localhost:3306/db1216";
	private static String user = "root";
	private static String password = "root";
	
	
	//注册驱动,只需要执行一次,不需要每次创建连接都注册一遍;
	static{
		try {
			Class.forName(drivername);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	//获取连接
	public static Connection getConnect() throws SQLException {
		Connection con = DriverManager.getConnection(url, user, password);
		System.out.println("数据库连接成功!");
		return con;
	}
	//关闭资源
	public static void CloseAll(Connection con,java.sql.Statement st,ResultSet rs) {
		try {
			if(rs != null) rs.close();
			if(st != null) st.close();
			if(con != null) con.close();
			System.out.println("已退出连接!");
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

//测试类
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Test {

	public static void main(String[] args) {
		Connection con = null;
		Statement st = null;
		ResultSet rs = null;
		
		try {
			con = JDBCUtils.getConnect();
			st = con.createStatement();
			rs = st.executeQuery("select * from person");
			
			while(rs.next()) {
				int pid = rs.getInt("pid");
				String pname = rs.getString("pname");
				int page = rs.getInt("page");
				String psex = rs.getString("psex");
				String format = "%d %s %d %s%n";
				System.out.printf(format, pid,pname,page,psex);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCUtils.CloseAll(con, st, rs);
		}
	}
}
	console结果:
	数据库连接成功!
	1 小明 18 男
	2 小华 20 男
	3 小红 18 女
	4 小芳 23 女
	5 小亮 17 男
	已退出连接!

4.PreparedStatement和Statement
示例:

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import JdbcUtils.JDBCUtils;

public class demo {

	public static void main(String[] args) {
		Connection con = null;
		PreparedStatement pst = null;
		ResultSet rs = null;
		Statement st = null;
		
		try {
			con = JDBCUtils.getConnect();
			//使用prepareStatement
			String sql = "insert into person(pid,pname,page,psex) values (?,?,?,?)";
			pst = con.prepareStatement(sql);
			pst.setInt(1, 6);
			pst.setString(2, "小苟");
			pst.setInt(3, 30);
			pst.setString(4, "人妖");
			pst.executeUpdate();
			
			//使用statement
			String sql2 ="insert into person (pid,pname,page,psex) values (" + 8 +"," + "'小亮'" + "," + 28 +"," + 
			"'男'" + ")";
			st = con.createStatement();
			st.executeUpdate(sql2);
			
			System.out.println("数据操作完成!");
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCUtils.CloseAll(con, pst, rs);
			JDBCUtils.CloseAll(con, st, rs);
		}

	}
	console结果:
	数据库连接成功!
	数据操作完成!
	已退出连接!

Statement与PreparedStatement区别:

  • Statement 需要进行字符串拼接,可读性和维护性比较差;PreparedStatement 使用参数设置,可读性好,不易犯错;
  • PreparedStatement有预编译机制,性能比Statement更快;
  • 防止SQL注入式攻击

5.execute与executeUpdate

execute与executeUpdate区别:

  • 相同点:都可以执行增加,删除,修改
  • 不同点1:
    execute可以执行查询语句 然后通过getResultSet,把结果集取出来 executeUpdate不能执行查询语句;
  • 不同点2:
    execute返回boolean类型,true表示执行的是查询语句,false表示执行的是insert,delete,update等等;
    executeUpdate返回的是int,表示有多少条数据受到了影响;

三、JDBC连接池(ConnectionPool)

1.连接池作用
1.1不使用连接池:当有多个线程,每个线程都需要连接数据库执行SQL语句的话,那么每个线程都会创建一个连接,并且在使用完毕后,关闭连接;
缺点:创建连接,关闭连接需要时间,同时也消耗系统资源;

1.2使用连接池:连接池在使用之前,就会创建好一定数量的连接。如果有任何线程需要使用连接,那么就从连接池里面借用,而不是自己重新创建。使用完毕后,又把这个连接归还给连接池供下一次或者其他线程使用。
优点:连接有借有还,效率高;

2.连接池规范
规范:Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口,这样应用程序可以方便的切换不同厂商的连接池。

常见的连接池:DBCP、C3P0;

3.DBCP连接池
DBCP是Apache开发的一个 Java 连接池项目,也是 tomcat 使用的连接池组件;
3.1 导入jar包:
导入commons-dbcp-1.4.jar和commons-pool-1.5.6.jar
3.2 添加配置文件:

  • 配置文件名称:*.properties
  • 配置文件位置:任意,建议src(classpath/类路径)
  • 配置文件内容:properties不能编写中文

3.3 BasicDataSource和BasicDataSourceFactory的开发过程:
不使用配置文件直接使用连接池类(BasicDataSource)的开发步骤:

  • 创建连接池对象:使用构造直接new一个对象
  • 注册驱动方法:public synchronized void setDriverClassName(String driverClassName)
  • 设置数据库URL:public synchronized void setUrl(String url)
  • 设置数据库User: public void setUsername(String username)
  • 设置数据库Password:public void setPassword(String password)
  • 获取连接对象:public Connection getConnection()
  • 关闭资源

使用配置文件需要连接池工厂类(BasicDataSourceFactory)的开发步骤:

  • 加载配置文件new Properties() .load(InputStream inStream)
  • 创建连接池方法(静态方法): public static DataSource createDataSource(Properties properties)
  • 获取连接对象:Connection getConnection()
  • 关闭资源

3.4 使用配置文件示例:

//DBCPUtils工具类
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;

public class DBCPUtils {
	private static DataSource ds = null;
	//获取连接池对象,仅需要创建一次连接池对象
	static {
		Properties config = new Properties();
		try {
			//配置文件必须要放在src目录下:因为getResourceAsStream()方法就是从src中获取配置文件再转流
			config.load(DBCPUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties"));
			ds = BasicDataSourceFactory.createDataSource(config);
			System.out.println("连接池已发出连接!");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	//从连接池获取连接
	public static Connection getConnection() throws SQLException {
		Connection con = ds.getConnection();
		System.out.println("数据库连接成功!");
		return con;
	}
	//关闭资源
	public static void CloseAll(Connection con,java.sql.Statement st,ResultSet rs) {
		try {
			if(rs != null) rs.close();
			if(st != null) st.close();
			if(con != null) con.close();
			System.out.println("已退出连接!");
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

//测试类
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class test {
	
	public static void main(String[] args) {
		Connection con = null;
		PreparedStatement pst = null;
		ResultSet exe = null;
		
		String sql = "select * from person";
		
		try {
			con = DBCPUtils.getConnection();
			pst = con.prepareStatement(sql);
			exe = pst.executeQuery();
			
			while(exe.next()) {
				int pid = exe.getInt("pid");
				String pname = exe.getString("pname");
				String format = "编号: %d 名字:%s%n";
				System.out.printf(format,pid,pname);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}

		DBCPUtils.CloseAll(con, pst, exe);
	}
}

记忆点:获取类对象有3种方式

  1. Class.forName
  2. 类名.class
  3. new 类名().getClass()

4. C3P0连接池
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。
3.1 导入jar包:
导入c3p0-0.9.1.2.jar 和 mchange-commons-java-0.2.11.jar
3.2 配置:
添加配置文件c3p0-config.xml到项目src目录下
3.3 开发过程:
连接池类:ComboPooledDataSource

  • 配置好xml文件(c3p0连接池是自动会送src目录下加载xml配置文件,不要像DBCP一样需要手动加载)
  • 创建连接池对象:直接new一个ComboPooledDataSource()
  • 获取连接
  • 关闭资源

3.4 示例:

//C3P0Utils工具类
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3P0Utils {
	
		private static ComboPooledDataSource cp = new ComboPooledDataSource();

		//从连接池获取连接
		public static Connection getConnection() throws SQLException {
			Connection con = cp.getConnection();
			System.out.println("数据库连接成功!");
			return con;
		}
		//关闭资源
		public static void CloseAll(Connection con,java.sql.Statement st,ResultSet rs) {
			try {
				if(rs != null) rs.close();
				if(st != null) st.close();
				if(con != null) con.close();
				System.out.println("已退出连接!");
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
}

5.普通连接和连接池的多线程测试:

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import DbcpUtils.DBCPUtils;
import JdbcUtils.JDBCUtils;

public class Test {

	public static void main(String[] args) {
		//测试多线程下,传统方式连接和连接池的性能差异
		//创建线程数组用来保存线程对象
		Thread[] Th = new Thread[100]; 
		//记录起始时间点
		long t1 = System.currentTimeMillis();
		
		//创建100组线程,每个线程都要运行“连接-执行SQL语句-关闭”完整访问数据库操作
		for(int i=0;i<100;i++) {
			Thread t = new Thread() {
				public void run() {
					System.out.println(this.getName()+"线程运行");
//						SimpleConnect();
						PoolConnect();
				}
			};
			t.start();
			Th[i] = t;
		}
		
		//等待所有线程结束
		for (Thread twait : Th) {
			try {
				twait.join(0);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		//记录结束时间点,并输出结果
		long t2 = System.currentTimeMillis();
		System.out.println("耗时:"+ (t2-t1) +"ms" );
	}
	
	public static void SimpleConnect() {
		Connection con = null;
		Statement st = null;
		ResultSet rs = null;
		
		try {
			con = JDBCUtils.getConnect();
			st = con.createStatement();
			rs = st.executeQuery("select * from person");
			
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JDBCUtils.CloseAll(con, st, rs);
		}
	}
	
	public static void PoolConnect() {
		Connection con = null;
		PreparedStatement pst = null;
		ResultSet exe = null;
		String sql = "select * from person";
		
		try {
			con = DBCPUtils.getConnection();
			pst = con.prepareStatement(sql);
			exe = pst.executeQuery();
			
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			DBCPUtils.CloseAll(con, pst, exe);
		}
	}
}

6.DBUtils工具类库
Commons DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能。
6.1 Dbutils三个核心:

  • QueryRunner类:提供对sql语句操作的API;
    构造:
    public QueryRunner(DataSource ds);
    public QueryRunner();
    方法:
    int update(String sql, Object… params)
    < T > T query(String sql, ResultSetHandler rsh, Object… params)

  • ResultSetHandler接口:用于定义select操作后,怎样封装结果集;
    主要的实现类:
    在这里插入图片描述

  • DbUtils类:一个工具类,定义了关闭资源与事务处理的方法;
    构造:

6.2 示例:
在这里插入图片描述

//JavaBean类
public class Identity implements java.io.Serializable{

	private static final long serialVersionUID = -8771783031495068229L;
	private int pid;
	private String pname;
	private int page;
	private String psex;
	public int getPid() {
		return pid;
	}
	public void setPid(int pid) {
		this.pid = pid;
	}
	public String getPname() {
		return pname;
	}
	public void setPname(String pname) {
		this.pname = pname;
	}
	public int getPage() {
		return page;
	}
	public void setPage(int page) {
		this.page = page;
	}
	public String getPsex() {
		return psex;
	}
	public void setPsex(String psex) {
		this.psex = psex;
	}
}
//测试类
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.ArrayHandler;
import org.apache.commons.dbutils.handlers.ArrayListHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ColumnListHandler;
import org.apache.commons.dbutils.handlers.MapHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import c3p0Utils.C3P0Utils;

public class Test {

	public static void main(String[] args) throws SQLException {
		ComboPooledDataSource ds = C3P0Utils.getDataSource();
		QueryRunner qr = new QueryRunner(ds);
		
//		insert(qr);
//		delete(qr);
//		update(qr);
		query(qr);
	}
	
	public static void insert(QueryRunner qr) throws SQLException {
		String sql = "insert into person (pid,pname,page,psex) values (?,?,?,?)";
		Object[] params = {9,"小美",6,"女"};
		
		int u = qr.update(sql, params);
		if(u>0) {
			System.out.println("已执行插入操作");
		}
	}
	
	public static void delete(QueryRunner qr) throws SQLException {
		String sql = "delete from person where pid = ?";
		Object[] params = {7};
		int u = qr.update(sql, params);
		if(u>0) {
			System.out.println("已执行删除操作");
		}
	}
	
	public static void update(QueryRunner qr) throws SQLException {
		String sql = "update person set page = ? where pid = ?";
		Object[] params = {40,2};
		int u = qr.update(sql, params);
		if(u>0) {
			System.out.println("已执行插入操作");
		}
	}
	
	public static void query(QueryRunner qr) throws SQLException {
		//ArrayHandler
		String sql1 = "select * from person where pid = ?";
		ResultSetHandler<Object[]> rsh1 =new ArrayHandler();
		Object[] params1 = {6};
		Object[] rs1 = qr.query(sql1, rsh1, params1);
		for (Object obj : rs1) {
			System.out.println(obj + " ");
		}
		
		//ArrayListHandler
		String sql2 = "select * from person";
		ArrayListHandler rsh2 = new ArrayListHandler();
		List<Object[]> rs2 = qr.query(sql2, rsh2);
		for (Object[] obj : rs2) {
			System.out.println(obj[0] +" " +obj[1] + " " + obj[2] + " " + obj[3]);
		}
		
		//BeanHandler
		String sql3 = "select *from person";
		BeanHandler<Identity> bh = new BeanHandler<Identity>(Identity.class);
		Object[] params3 = null;
		Identity rs3 = qr.query(sql3, bh, params3);
		System.out.println(rs3.getPname());
		//BeanListHandler
		String sql4 = "select *from person";
		BeanListHandler<Identity> blh = new BeanListHandler<Identity>(Identity.class);
		Object[] params4 = null;
		List<Identity> rs4 = qr.query(sql4, blh, params4);
		for (Identity id : rs4) {
			System.out.println(id.getPname());
		}
		
		//ColumnListHandler
		String sql5 = "select *from person";
		ColumnListHandler<String> clh = new ColumnListHandler<String>("pname");
		Object[] params5 = null;
		List<String> rs5 = qr.query(sql5, clh,params5);
		System.out.println(rs5);
		
		//MapHandler
		String sql6 = "select *from person";
		MapHandler mh = new MapHandler();
		Object[] params6 = null;
		Map<String, Object> rs6 = qr.query(sql6, mh, params6);
		System.out.println(rs6);
		
		//MapListHandler
		String sql7 = "select *from person";
		MapListHandler mlh = new MapListHandler();
		Object[] params7 = null;
		List<Map<String, Object>> rs7 = qr.query(sql7, mlh, params7);
		for (Map<String, Object> obj : rs7) {
			System.out.println(obj);
		}
		
		//ScalarHandler
		String sql8 = "select count(*) from person";
		ScalarHandler<Long> sh = new ScalarHandler<Long>();
		Object[] params8 = null;
		Long rs8 = qr.query(sql8, sh, params8);
		System.out.println("总行数:"+rs8);
	}

}

console结果:
6 
小苟 
30 
人妖 
1 小明 18 男
2 小华 40 男
3 小红 18 女
4 小芳 23 女
5 小亮 17 男
6 小苟 30 人妖
8 小亮 28 男
9 小美 6 女
小明
小明
小华
小红
小芳
小亮
小苟
小亮
小美
[小明, 小华, 小红, 小芳, 小亮, 小苟, 小亮, 小美]
{pid=1, pname=小明, page=18, psex=男}
{pid=1, pname=小明, page=18, psex=男}
{pid=2, pname=小华, page=40, psex=男}
{pid=3, pname=小红, page=18, psex=女}
{pid=4, pname=小芳, page=23, psex=女}
{pid=5, pname=小亮, page=17, psex=男}
{pid=6, pname=小苟, page=30, psex=人妖}
{pid=8, pname=小亮, page=28, psex=男}
{pid=9, pname=小美, page=6, psex=女}
总行数:8

四、事务

1.概述
1.1 概念: 事务指的是逻辑上的一组操作(多条sql语句),组成这组操作的各个单元要么全都成功,要么全都失败。
1.2 作用: 保证在一个事务中多次操作要么全都成功,要么全都失败。比如银行转账,要么转账成功要么转账失败,不能出现一方扣款成功,另一方没有收款,那么转账整个过程就可以看成是一个事务;

2.MySql事务
在这里插入图片描述
2.1 使用DBUtils示例:
在这里插入图片描述

//借助ThreadLocal创建的连接管理类
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import c3p0Utils.C3P0Utils;

public class Test {

	public static void main(String[] args) {
		Connection con = null;
		try {
			//获取连接
			con = C3P0Utils.getConnection();
			//关闭自动提交事务就等于开启事务
			con.setAutoCommit(false);
			//转账
			transfer(con);
			//提交事务
			con.commit();
			System.out.println("转账成功!");
		} catch (Exception e) {
			System.out.println("转账失败,进行回滚");
			//回滚事务
			try {
				con.rollback();
			} catch (SQLException e1) {
				System.out.println("回滚失败!");
			}
		}
		
	}
	
	public static void transfer(Connection conn) throws SQLException {
		deduction(conn);
		collection(conn);
	}
	//扣款
	public static void deduction(Connection conn) throws SQLException {
		QueryRunner qr = new QueryRunner();
		String sql = "update account set total=total-? where name=?";
		Object[] params = {10000,"kate"};
		
		qr.update(conn, sql , params);
//		System.out.println(1/0);//测试转账过程中出现异常
	}
	//收款
	public static void collection(Connection conn) throws SQLException {
		QueryRunner qr = new QueryRunner();
		String sql = "update account set total=total+? where name=?";
		Object[] params = {10000,"jack"};
		
		qr.update(conn, sql , params);
	}

}

2.2 事务特性:

  • 原子性:强调事务的不可分割.多条语句要么都成功,要么都失败;
  • 一致性:强调的是事务的执行的前后,数据要保持一致;
  • 隔离性:一个事务的执行不应该受到其他事务的干扰;
  • 持久性:事务一旦结束(提交/回滚)数据就持久保持到了数据库;

2.3 安全性:
存在的问题:

  • 脏读 :一个事务读到另一个事务还没有提交的数据;
  • 不可重复读 :一个事务读到了另一个事务已经提交的update的数据,导致在当前的事务中多次查询结果不一致;
  • 虚读/幻读 :一个事务读到另一个事务已经提交的insert的数据,导致在当前的事务中多次的查询结果不一致;

设置事务的隔离级别:

  • 1 read uncommitted :未提交读.脏读,不可重复读,虚读都可能发生;
  • 2 read committed :已提交读.避免脏读.但是不可重复读和虚读有可能发生.(Oracle默认);
  • 4 repeatable read :可重复读.避免脏读,不可重复读.但是虚读有可能发生.(MySql默认);
  • 8 serializable :串行化的.避免脏读,不可重复读,虚读的发生.;
    级别超高,越安全,效率越低;设置隔离级别必须在事务之前;

MySql事务隔离语句:

  • 查看当前的事务隔离级别:SELECT @@TX_ISOLATION;
  • 更改当前的事务隔离级别:SET TRANSACTION
  • ISOLATION LEVEL 四个级别之一;

3.初涉三层架构(3-tier architecture)
3.1 三层架构思想:高内聚、低耦合
3.2 具体分类:持久层(DAO层)、业务层(service层)、表现层(view层)
3.3 示例:

import java.sql.Connection;
import java.sql.SQLException;
import c3p0Utils.C3P0Utils;

public class ConManager {
	private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
	
	public static Connection getCon() throws SQLException {
		//获取连接,并保存在当前线程下的局部变量中
		Connection con = tl.get();
		if(con == null){
			con = C3P0Utils.getConnection();
			tl.set(con);
		}
		return con;
	}
	
	public static void start() throws SQLException {
		//关闭自动提交事务就等于开启事务
		ConManager.getCon().setAutoCommit(false);
	}
	
	public static void commit() throws SQLException {
		//提交事务
		ConManager.getCon().commit();
	}
	
	public static void rollback() throws SQLException {
		//回滚事务
		ConManager.getCon().rollback();
	}
	
	public static void close() {
		try {
			ConManager.getCon().close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

//DAO层
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import Service.ConManager;

public class Db {
	//扣款
	public static void deduction(int num,String name) throws SQLException {
		Connection conn = ConManager.getCon();
		QueryRunner qr = new QueryRunner();
		String sql = "update account set total=total-? where name=?";
		
		qr.update(conn, sql , num , name);
//		System.out.println(1/0);
	}
	//收款
	public static void collection(int num,String name) throws SQLException {
		Connection conn = ConManager.getCon();
		QueryRunner qr = new QueryRunner();
		String sql = "update account set total=total+? where name=?";
		
		qr.update(conn, sql , num , name);
	}
}
//业务层
import java.sql.SQLException;
import Dao.Db;

public class Ser {
	
	public static void transfer(String dname,int num,String cname){
		
		try {
			ConManager.start();
			//转账
			Db.deduction(num,dname);
			Db.collection(num,cname);
			System.out.println("转账成功");
			ConManager.commit();
		} catch (Exception e) {
			System.out.println("转账失败,进行回滚");
			//回滚事务
			try {
				ConManager.rollback();
			} catch (SQLException e1) {
				System.out.println("回滚失败!");
			} finally {
				ConManager.close();
			}
		}
	}
}
//表现层
import Service.Ser;

public class Vi {

	public static void main(String[] args) {
		int num = 2000;
		String dname = "jack";
		String cname = "tom";
		
		Ser.transfer(dname,num,cname);
	}
}

4.ThreadLocal类
4.1 方法:
T get() :返回当前线程的此线程局部变量的副本中的值
protected T initialValue() :返回此线程局部变量的当前线程的“初始值”
void remove() :删除此线程局部变量的当前线程的值
void set(T value) :将当前线程的此线程局部变量的副本设置为指定的值
static < S > ThreadLocal< S > withInitial(Supplier<? extends S> supplier) :创建线程局部变量

4.2 为什么上例中需要用ThreadLocal?

  • 线程安全问题:DBUtils示例在单线程使用中是没有问题的,但是在多线程中,创建的某个数据库连接就可能会被多个线程共用比如某个线程刚开启的连接被另一个线程关闭;
  • 解决措施:
    1)是否可以使用同步:需要调用数据库连接的地方都进行同步,这样是解决安全问题但是效率太低,因为只能一个线程在使用连接操作数据库,其他线程只能等待;
    2)使用ThreadLocal:ThreadLocal在每个线程中对该变量会创建一个副本,即每个线程内部都会有一个该变量,且在线程内部任何地方都可以使用,线程之间互不影响,这样一来就不存在线程安全问题,也不会严重影响程序执行性能。

4.3 ThreadLocal类内部原理:

在这里插入代码片
DBUtils的Jar包 commons-dbutils-1.4DBUtils是对JDBC的简单封装DBUtils是Apache Commons组件中的一员 立即下载

相关推荐

Dbutils 的jar包

queryRunnner数据库连接池jar

commons-dbutils-1.3.jar下载

Commons-dbutils-1.3.jar 可以在 Apache 的官方网站上下载。您可以访问以下链接: http://commons.apache.org/proper/commons-dbutils/download_dbutils.cgi 请确保您下载的版本为 1.3,并且根据自己的需要选择合适的文件。 下载后,您可以将其添加到您的项目中并使用它。 ...

weixin_42576467的博客 1574

DBUtils-jar包.zip

Apache-DBUtils-jar包

DbUtils jar包下载

方法一:链接直达 方法二:官网 链接直达 直接下载地址:http://commons.apache.org/proper/commons-dbutils/download_dbutils.cgi   官网 当然第一种也是官网 进入官网首页http://apache.org/ 找到Commons 找到DbUtils下载    ...

小猪的日常Java 3万+

DBUtils工具包(Jar包及帮助文档)

Commons DbUtils 是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化 JDBC应用程序的开发,同时也不会影响程序的性能。亲测可用,放心使用!

dbutils jar包及使用介绍

commons-dbutils-1.6 的jar包及相关使用介绍文档,底层开发的可以用下

commons-dbutils-1.3.jar 包官网下载

下载好之后解压文件,打开文件在里面找到 复制到编辑器ibs文件中即可。

EGO_KUN的博客 1584

Commons-dbutils1.7 jar包.rar

commons-dbutils包是Apache开源组织提供的用于操作数据库的工具包。简单来讲,这个工具包就是用来更加方便我们操作数据库的,最近工作中使用了一下,感觉确实方便很多,基本告别自己封装JDBC代码对数据库进行增删改查了。代码看着也很简洁。 例如: 增删改查使用的类:QueryRunner类+ResultSetHandler类,使用这俩类就可以解决掉。 QueryRunner类的query()方法:new QueryRunner().query(Connection conn, String sql, ResultSetHandler rsh) query方法后面参数中加一个Connection连接,是在获取不到数据源的情况下,也就是说,QueryRunner的实例化构造函数使用无参的那个,下面我的实现代码就是用的这种方法。 当然还有一种实例化:new QueryRunner(new Datasource()).query(String sql, ResultSetHandler rsh) query方法中的参数 ResultSetHandler 参数中加上ResultSetHandler接口的实现类参数(下面这些实现类),执行完SQL后,返回的数据就是已经封装好的我们想要的结果了。 ArrayHandler :将ResultSet中第一行的数据转化成对象数组 ArrayListHandler将ResultSet中所有的数据转化成List,List中存放的是Object[] BeanHandler :将ResultSet中第一行的数据转化成Bean对象 BeanListHandler :将ResultSet中所有的数据转化成List ColumnListHandler :将ResultSet中某一列的数据存成List KeyedHandler :将ResultSet中存成映射,key为某一列对应为Map,Map中存放的是数据 MapHandler :将ResultSet中第一行的数据存成Map MapListHandler :将ResultSet中所有的数据存成List<Map> ScalarHandler :将ResultSet中一条记录的其中某一列的数据存成Object

超详细的JDBC基础,内含 C3P0 和 Druid 等 工具类 JAR 包下载

JDBC基础笔记,内包含多个连接池下载地址和多个工具类的下载地址和使用

jmgufss的博客 4958

大样本EEG公共数据集汇总

描述: OpenNeuro平台包含多个认知障碍相关的EEG数据集,例如针对轻度认知障碍(MCI)或阿尔茨海默病(AD)的研究。描述: 天普大学医院EEG语料库包含大量临床EEG记录,可通过元数据筛选出与认知障碍相关的片段(如诊断标签包含dementia或MCI)。描述: ADNI主要提供多模态神经影像数据(MRI/PET),但部分合作研究整合了EEG数据。样本量: 部分数据集包含100+被试(例如结合MRI与EEG的多模态数据)。样本量:30,000+ EEG记录(持续更新,全球最大临床EEG数据库)。

谁人打的太极拳的博客 1759

PL端:HDMI 输出实验

开发板没有HDMI编码芯片,是将FPGA的3.3差分IO直接连接到HDMI连接器,FPGA 完成 24 位 RGB 编码输出TMDS 差分信号。1、学会使用第三点IP核,首先是添加,后面的使用和自带IP核操作一致。2、主要还是在梳理vivado使用流程。

qq_43441284的博客 4287

【Java】JDBC全面指南 —— 你的JDBC学习终点站

【Java】JDBC全面指南 —— 你的JDBC学习终点站 去发现同类优质开源项目:https://gitcode.com/ 欢迎来到这篇详尽的JDBC教程!无论你是Java新手,还是想要回顾数据库操作的老手,这里都为你提供了一站式的解决方案。本文档旨在帮助你掌握Java Database Connectivity (JDBC)的基础知识及高级应用,使你能自信地在Java项目中管理数据库。 内容概...

gitblog_06585的博客 898

深入解析CAN总线BusOff故障的检测与恢复机制

本文深入解析了CAN总线BusOff故障的检测与恢复机制。BusOff是CAN节点因发送错误过多而被强制离线的一种严重状态。文章详细阐述了其触发原理,即发送错误计数器(TEC)超过255,并重点介绍了通过软件实现的快慢恢复机制,以增强网络在异常情况下的稳定性和韧性。

weixin_29158047的博客 523

Java学习笔记之jdbc

JDBC学习 jdbc是什么 ​ JDBC: java database connectivity java 与数据库的连接 ​ jdbc承载着数据库与java之间的连接 jdbc连接步骤 Class.forName() public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, SQLException, IOException

weixin_44460816的博客 122

如何把ORCAD 中的修改同步到PADS 中

Generate ECO file(*.eco),eco 文件的默然保存地址是在pads 的。ECO Files (*.eco),接着在文件中找到所生成的eco 文件,找到。再下来是产生eco 文件,先打开old_design.pcb,然后选择。PCB Design 前面的选项选中,意思把当前文件做为原始的比对。安装目录下(可修改eco 文件的保存目录),这里把eco 文件保存。接下来用新生成asc 文件的文件产生新的PCB 文件,新生成。不对新生成的pcb 做任何的修改,直接保存文件,这里把新文件。

智光工作室 993

小米手机安装Burp证书失败原因与DER格式改造指南

CA证书是HTTPS抓包和移动安全测试的基础组件,其本质是遵循X.509标准的数字凭证,依赖ASN.1/DER编码格式与完整证书链实现可信验证。Android系统默认支持PEM和DER两种编码,但MIUI自14版本起强化安全策略,仅识别DER二进制格式,并强制校验Subject Alternative Name(SAN)、Basic Constraints及证书链完整性。这种企业级加固逻辑导致Burp Suite导出的PEM格式.cer文件在小米设备上‘安装成功但无效’。本文聚焦证书格式转换、SAN字段注入

weixin_33646989的博客 625

JAVA-JDBC连接和相关学习

JAVA-JDBC连接和相关学习 文章目录JAVA-JDBC连接和相关学习JDBC基本连接方式SQL语句Statement和preparedStatement区别execute与executeUpdate的区别事务ORMDAO数据库连接池 JDBC基本连接方式 首先准备工作下载安装Mysql或者其他数据库,其次导入 mysql-connector-java-5.0.8-bin.jar 或其他第三方包(用于驱动) 然后连接: Connection connection = null; PreparedSt

IIKY的博客 1681

SD-WAN组网案例——数据中心

SD-WAN组网案例——数据中心

2301_78457663的博客 705

Java学习之JDBC基本使用

JDBC中如何连接数据库及ResultSet、Statement、PrepareStatement、事务、批处理的基本使用

404 Not Found 1078

Sylvester结式法求解多项式方程

Sylvester结式法,结式,消元法,ctfshow 七夕杯 LUCK7,crypto,WriteUp

u010883831的博客 4531

Unity 2D精灵点击交互实现:从BoxCollider 2D到Event Trigger的完整指南

本文提供了Unity 2D精灵点击交互的完整实现指南。通过详细拆解BoxCollider 2D与Event Trigger两大核心组件的协同工作原理,手把手教你为Sprite Renderer添加点击、悬停等事件响应。文章包含从基础配置到进阶优化、性能调试的实战步骤,帮助开发者高效实现游戏世界内的对象交互,是Unity 2D开发的实用教程。

ansible6ops的博客 301

Java07学习(JDBC、Maven)

定义:是一种用于执行SQL语句的JAVA API,为多种关系数据库提供统一的访问,它由一组用Java语言编写的类和接口组成。JDBC:Java DataBase Connectivity(java数据库连接)早期:java在连接不同的数据库,都要根据不同数据库的规则写对应的代码,进行连接;JDBC之后:java制定一系列的连接数据库的规范(接口),不同的数据库根据java规范写实现类;优点是java中可以使用同一套编码、API、写法来连接数据库,更加的方便、操作减少。例子:形象比喻。

weixin_73416102的博客 626

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

jsp servlet jdbc java基础学习

jsp servlet jdbc java基础学习

ccecwg的专栏 674

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

Java学习之JDBC

Java学习之JDBC想写这类文章一经很久了,一直没时间,其实也不是真的没时间,只是感觉太累了,而且自己学的不够深,就一直搁浅。算下来,从真的开始学习写代码到现在已经四年了。 这四年从c++开始入门,然后学习了Linux,然后搞了几天win32,学习c++一年半,辞职准备考研,折腾了几天php(现在也就只能看懂php代码了),到准备考研一半,又工作。 这次工作给我带来了不少的收获,让我真正的有所

ysflizi的专栏 7838

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

【Java学习笔记】71 - JDBC入门

1. JDBC为访问不同的数据库提供了统一的接口,为使用者屏蔽了细节问题。2. Java程序员使用JDBC,可以连接任何提供了JDBC驱动程序的数据库系统,从而完成对数据库的各种操作。3. JDBC的基本原理(原理)4.模拟JDBC1.表示数据库结果集的数据表,通常通过执行查询数据库的语句生成2. ResultSet对象保持一个光标指向其当前的数据行。最初,光标位于第一行之前。

qq_41891655的博客 1368

Java JDBC再学习

目录前言学习内容测试使用JDBC 前言 学习Java的对于JDBC肯定不会陌生。Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。JDBC也是Sun Microsystems的商标。我们通常说的JDBC是面向关系型数据库的。 学习内容 测试使用JDBC 相关操作建议参照!!! 参考文章链接 新建项目结构如下,引入jar包到lib文件下; 设置jar包到项

小柯的的博客 7078
上一篇: Java学习-Lambda表达式
下一篇: Java学习-反射
Jagger_Lin
博客等级 码龄8年 17粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值