事务 && 数据库连接池 && DBUtils && 装饰模式

                                                      事务

Transaction :

其实指的一组操作,里面包含许多个单一的逻辑。只要有一个逻辑没有执行成功,那么都算失败。 所有的数据都回归到最初的状态(回滚)。

为什么要有事务?

为了确保逻辑的成功。 例子: 银行的转账。 

使用命令行方式演示事务

* 开启事务

    start transaction;

* 提交或者回滚事务

    commit; 提交事务, 数据将会写到磁盘上的数据库
    rollback ;  数据回滚,回到最初的状态。

 1. 关闭自动提交功能

2. 演示事务

使用代码方式演示事务

代码里面的事务,主要是针对连接来的

1.  通过conn.setAutoCommit(false )来关闭自动提交的设置。

2. 提交事务  conn.commit();

3. 回滚事务 conn.rollback();

实例:TransactionDemo01/src/it/cast/test/demo/TestDemo01.java

public class TestDemo01 {
	@Test
	public void testTransaction() {
		
		Connection conn =null;
		PreparedStatement ps =null;
		try {
			conn = JDBCUtil.jdbcConn();
			//jdbc默认的实物事物是自动提交的,关闭自动提交的功能
			conn.setAutoCommit(false);
			
			String sql="update account set mony = mony-? where id= ?";
			ps = conn.prepareStatement(sql);
			
			//给id为1的账户增加100元
			ps.setInt(1, 100);
			ps.setInt(2, 1);
			ps.executeUpdate();
			
			int a=10/0;//设置的错误
			
			//给id为2的账户减少100元
			ps.setInt(1, -100);
			ps.setInt(2, 2);
			ps.executeUpdate();
			
			//提交事务
			conn.commit();
			
		} catch (SQLException e) {
			try {
				//如果发生错误,数据回滚
				conn.rollback();
			} catch (SQLException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			e.printStackTrace();
		}finally {
			JDBCUtil.resease( ps, conn);
		}
	}
}

事务的特性

* 原子性

> 指的是 事务中包含的逻辑,不可分割。 

* 一致性

> 指的是 事务执行前后。数据完整性保持一致

* 隔离性

> 指的是 事务在执行期间不应该受到其他事务的影响

* 持久性

> 指的是 事务执行成功,那么数据应该持久保存到磁盘上。

事务的安全隐患 

不考虑隔离级别设置,那么会出现以下问题。

* 读
          脏读:一个事务读到了另外一个未提交的并行事务写的数据。

          不可重复读 :一个事务读到了另外一个事务提交的数据 ,造成了前后两次查询结果不一致。

          幻读:一个事务读到了另一个事务insert的数据 ,造成前后查询结果不一致 。

* 写

      丢失更新

隔离级别

    Read Uncommitted:读未提交

             引发问题: 脏读 
    Read Committed:读已提交【oracle默认】

             解决: 脏读 , 引发: 不可重复读
    Repetable:重复读【mysql默认】

             解决: 脏读 、 不可重复读 , 未解决: 幻读
             该事务级别不受其他事务的影响,在本次连接状态下,即使其他的事务连接修改了数据,本次读到的数据也不会改变,                 和上次查询结果一致。
    Seializable:可串行化

             解决: 脏读、 不可重复读 、 幻读。

 mySql 默认的隔离级别是 可重复读

 Oracle 默认的隔离级别是  读已提交

读未提交 演示:

1. 设置A窗口的隔离级别为 读未提交 

2. 两个窗口都分别开启事务

读已提交演示 

1. 设置A窗口的隔离级别为 读已提交

2. A B 两个窗口都开启事务, 在B窗口执行更新操作。

3. 在A窗口执行的查询结果不一致。 一次是在B窗口提交事务之前,一次是在B窗口提交事务之后。

 这个隔离级别能够屏蔽 脏读的现象, 但是引发了另一个问题  ,不可重复读。

可串行化

如果有一个连接的隔离级别设置为了串行化 ,那么谁先打开了事务, 谁就有了先执行的权利, 谁后打开事务,谁就只能得着,等前面的那个事务,提交或者回滚后,才能执行。  但是这种隔离级别一般比较少用。 容易造成性能上的问题。 效率比较低。按

* 按效率划分,从高到低

> 读未提交  > 读已提交  > 可重复读  > 可串行化

* 按拦截程度 ,从高到底

> 可串行化 > 可重复读 > 读已提交 >  读未提交

需要掌握的

1. 在代码里面会使用事务 

        conn.setAutoCommit(false);

        conn.commit();

        conn.rollback();

2. 事务只是针对连接连接对象,如果再开一个连接对象,那么那是默认的提交。

3. 事务是会自动提交的。 

丢失更新

解决丢失更新

* 悲观锁

> 可以在查询的时候,加入 for update
 

* 乐观锁

> 要求程序员自己控制。 (需要额外加一个字段)



                                         数据库连接池

1. 数据库的连接对象创建工作,比较消耗性能。 

2.一开始现在内存中开辟一块空间(集合) , 一开先往池子里面放置 多个连接对象。  后面需要连接的话,直接从池子里面去。不要去自己创建连接了。  使用完毕, 要记得归还连接。确保连接对象能循环利用。

自定义数据库连接池 

代码实现:ConnectionPool01/src/it/cast/connectionpool/demo1/MyDataSource.java

/**
 * 这是一个数据库连接池,一开始池子里面有10个连接:
 * 1.开始创建10个连接
 * 2.用getConnection获取连接
 * 3.用addBack的方法归还连接
 * 4.扩容
 */
public class MyDataSource implements DataSource{

	List<Connection>list=new ArrayList<Connection>();
	
	//一开始在构造方法创建10个连接
	public MyDataSource() {
		super();
		for (int i = 0; i < 5; i++) {
			Connection conn = JDBCUtil.jdbcConn();
			list.add(conn);
		}
	}

	//连接池对外公布获取连接的方法
	public Connection getConnection() throws SQLException {
		//扩容方法
		//连接的时候,看池子里面还有连接吗 
		if(list.size()==0) {
			for (int i = 0; i < 10; i++) {
				Connection conn = JDBCUtil.jdbcConn();
				list.add(conn);
			}
		}
		Connection conn=list.remove(0);
		return conn;
	}
	
	//连接池对外提供归还连接的方法
	public void addBack(Connection conn) {
		list.add(conn);
	}

简单的测试连接池:ConnectionPool01/src/it/cast/connectionpool/demo1/TestPool.java

public class TestPool {
	
	@Test
	public void tsetPool() {
		MyDataSource myDataSource=new MyDataSource();
		Connection conn=null;
		PreparedStatement rs = null;
		try {
			conn=myDataSource.getConnection();
			String sql="insert into account values(null,'xilali',10)";
			rs = conn.prepareStatement(sql);
			rs.executeUpdate();
			
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			//归还连接对象
			myDataSource.addBack(conn);
			try {
				rs.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
//			JDBCUtil.resease(st, conn);
		}
	}
}

出现的问题:

    1. 需要额外记住 addBack方法
 
     2. 单例。
 
     3. 无法面向接口编程。 
 
         UserDao dao = new UserDaoImpl();
         dao.insert();
         DataSource dataSource = new MyDataSource(); 
         因为接口里面没有定义addBack方法。 
 
     4. 怎么解决?   以addBack 为切入点。

解决自定义数据库连接池出现的问题。 

> 由于多了一个addBack 方法,所以使用这个连接池的地方,需要额外记住这个方法,并且还不能面向接口编程。

> 我们打算修改接口中的那个close方法。  原来的Connection对象的close方法,是真的关闭连接。 
> 打算修改这个close方法,以后在调用close, 并不是真的关闭,而是归还连接对象。

如何扩展某一个方法?

> 原有的方法逻辑,不是我们想要的。 想修改自己的逻辑

1. 直接改源码  无法实现。

2. 继承, 必须得知道这个接口的具体实现是谁。 

3. 使用装饰者模式

装饰着模式举例:WraperDemo

接口:Witer

public interface Waiter {
	void service();
}

实现该接口的子类:Witress

public class Witress implements Waiter {
	//女服务员
	public void service() {
		System.out.println("我来为你服务");
	}
}

装饰类:WaitressWraper

public class WaitressWraper implements Waiter{

	Waiter waiter;
	public WaitressWraper(Waiter waiter) {
		super();
		this.waiter = waiter;
	}

	@Override
	public void service() {
		System.out.println("开心");
		waiter.service();
	}
}

测试方法:TestWraper

public class TestWraper {	
	@Test
	public void testWraper() {
		//传入的是女服务员
		WaitressWraper waitressWraper=new WaitressWraper(new Witress());
		waitressWraper.service();
	}
}

使用装饰着模式改善自定义数据库:ConnectionPool2

连接池:MyDataSource

public class MyDataSource implements DataSource{

	List<Connection>list=new ArrayList<Connection>();
	
	//一开始在构造方法创建10个连接
	public MyDataSource() {
		super();
		for (int i = 0; i < 10; i++) {
			Connection conn = JDBCUtil.jdbcConn();
			list.add(conn);
		}
	}

	//连接池对外公布获取连接的方法
	public Connection getConnection() throws SQLException {
		//扩容方法
		//连接的时候,看池子里面还有连接吗 
		if(list.size()==0) {
			for (int i = 0; i < 5; i++) {
				Connection conn = JDBCUtil.jdbcConn();
				list.add(conn);
			}
		}
		//去除list集合中的第一个链接对象
		Connection conn=list.remove(0);
		//在把值传出去之前需要包装一下
		Connection connection = new WraperMaDataSource(conn, list);
		return connection;
	}
	
	//连接池对外提供归还连接的方法
	public void addBack(Connection conn) {
		list.add(conn);
	}
	

连接池的装饰类:WraperMaDataSource

public class WraperMaDataSource implements Connection{

	Connection conn=null;
	List<Connection>list=new ArrayList<>();
	
	public WraperMaDataSource(Connection conn, List<Connection> list) {
		super();
		this.conn = conn;
		this.list = list;
	}
	
	//装饰类的close方法,归还连接对象
	@Override
	public void close() throws SQLException {
		System.out.println("使用close前list集合中的连接对象个数"+list.size());
		list.add(conn);
		System.out.println("使用close后list集合中的连接对象个数"+list.size());
	}
	//因为之后需要用到这个方法,所以复写它
	public PreparedStatement prepareStatement(String sql) throws SQLException {
		
		return conn.prepareStatement(sql);
	}
	

简单的测试连接池:TestPool

public class TestPool {
	
	@Test
	public void tsetPool() {
		MyDataSource myDataSource=new MyDataSource();
		Connection conn=null;
		PreparedStatement ps = null;
		try {
			conn=myDataSource.getConnection();
			String sql="insert into account values(null,'shei',10)";
			ps = conn.prepareStatement(sql);
			ps.executeUpdate();
			
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCUtil.resease(ps, conn);
		}
	}
}

开源连接池

 DBCP

1. 导入jar文件

commons-dbcp-1.4.jar

commons-pool-1.5.6.jar

2. 不使用配置文件

public class DBCPDemo01 {
	@Test
	public void testDBCP01() {
		
		Connection conn = null;
		PreparedStatement ps = null;	
		try {
			BasicDataSource dataSource=new BasicDataSource();
			//代码配置
			dataSource.setUrl("jdbc:mysql://localhost/bank");
			dataSource.setUsername("root");
			dataSource.setPassword("19930903");
			dataSource.setDriverClassName("com.mysql.jdbc.Driver");
			
			conn = dataSource.getConnection();
			String sql="insert into account values(null,?,?)";
			ps = conn.prepareStatement(sql);
			ps.setString(1, "xiao");
			ps.setInt(2, 65);
			ps.executeUpdate();
			
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			JDBCUtil.resease(ps, conn);
		}
	}
}

使用配置文件连接:dbcpconfig.properties

#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/bank
username=root
password=

#<!-- 初始化连接 -->
initialSize=10

#最大连接数量
maxActive=50

#<!-- 最大空闲连接 -->
maxIdle=20

#<!-- 最小空闲连接 -->
minIdle=5

#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000

#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] 
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=gbk

#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true

#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED
public class DBCPDemo02 {
	@Test
	public void testDBCP02() {
		
		Connection conn = null;
		PreparedStatement ps = null;	
		try {
			BasicDataSourceFactory factory=new BasicDataSourceFactory();
			Properties properties=new Properties();
			InputStream is=new FileInputStream("src//dbcpconfig.properties");
			properties.load(is);
			DataSource dataSource = factory.createDataSource(properties);
			
			conn = dataSource.getConnection();
			String sql="insert into account values(null,?,?)";
			ps = conn.prepareStatement(sql);
			ps.setString(1, "dao");
			ps.setInt(2, 65);
			ps.executeUpdate();
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			JDBCUtil.resease(ps, conn);
		}
	}
}

C3P0

使用代码的方式使用C3P0数据库池

public class C3P0Demo1 {
	@Test
	public void testC3P01() {
		
		PreparedStatement ps = null;
		Connection conn =null;
		try {
			//获取datasource
			ComboPooledDataSource dataSource=new ComboPooledDataSource();
			//设立连接参数
			dataSource.setJdbcUrl("jdbc:mysql://localhost/bank");
			dataSource.setUser("root");
			dataSource.setPassword("19930903");
			dataSource.setDriverClass("com.mysql.jdbc.Driver");
			//得到连接对象
			conn = dataSource.getConnection();
			String sql="insert into account values(null,?,?)";
			ps = conn.prepareStatement(sql);
			ps.setString(1, "haha");
			ps.setInt(2, 65);
			ps.executeUpdate();
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			JDBCUtil.resease(ps, conn);
		}
	}
}

使用XML配置文件的形式连接数据库

配置文件:c3p0-config.xml    【名字必须是这个】

<?xml version="1.0" encoding="UTF-8"?>

<c3p0-config>
  <default-config>
    <property name="jdbcUrl">jdbc:mysql://localhost/bank</property>
    <property name="user">root</property>
    <property name="password">19930903</property>
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    
    <property name="initialPoolSize">10</property>
    <property name="maxIdleTime">30</property>
    <property name="maxPoolSize">100</property>
    <property name="minPoolSize">10</property>
    <property name="maxStatements">200</property>

  </default-config>
</c3p0-config>
	
public class C3P0Demo2 {
	
	@Test	
	public void testC3P02() {
		
		PreparedStatement ps = null;
		Connection conn =null;
		try {
			//获取datasource
			ComboPooledDataSource dataSource=new ComboPooledDataSource();
			//得到连接对象
			conn = dataSource.getConnection();
			String sql="insert into account values(null,?,?)";
			ps = conn.prepareStatement(sql);
			ps.setString(1, "haha");
			ps.setInt(2, 65);
			ps.executeUpdate();
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			JDBCUtil.resease(ps, conn);
		}
	}
}

原先的JDBCUtil的改变:不需要最初的配置文件了

public class JDBCUtil {
	
	static ComboPooledDataSource dataSource=null;
	static {
		dataSource=new ComboPooledDataSource();
	}
	/*
	 * jabc的连接 
	 */
	public static Connection jdbcConn() throws SQLException {
		
		return dataSource.getConnection();
	}
	/*
	 * 关闭数据库的方法,释放资源
	 */
	public static void resease(ResultSet rs,Statement st,Connection conn) {
		rsclose(rs);
		stclose(st);
		connclose(conn);
	}
	public static void resease(Statement st,Connection conn) {
		stclose(st);
		connclose(conn);
	}
	private static void rsclose(ResultSet rs) {
		try {
			if(rs!=null)
			rs.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	private static void stclose(Statement st) {
		try {
			if(st!=null)
				st.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	private static void connclose(Connection conn) {
		try {
			if(conn!=null)
				conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}	
}


                                                DBUtils

增删改:

		//dbutils 只是帮我们简化了CRUD 的代码, 但是连接的创建以及获取工作。 不在他的考虑范围
		QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
	
		//增加
		queryRunner.update("insert into account values (null , ? , ? )", "aa" ,1000);
		
		//删除
		queryRunner.update("delete from account where id = ?", 5);
		
		//更新
		queryRunner.update("update account set money = ? where id = ?", 10000000 , 6);

查询:

1. 直接new接口的匿名实现类

		QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
		Account  account =  queryRunner.query("select * from account where id = ?", new ResultSetHandler<Account>(){

			@Override
			public Account handle(ResultSet rs) throws SQLException {
				Account account  =  new Account();
				while(rs.next()){
					String name = rs.getString("name");
					int money = rs.getInt("money");
					
					account.setName(name);
					account.setMoney(money);
				}
				return account;
			}			 
		 }, 6);		
		System.out.println(account.toString());

2. 直接使用框架已经写好的实现类。

    * 查询单个对象

		QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
		//查询单个对象
		Account account = queryRunner.query("select * from account where id = ?", 
		new BeanHandler<Account>(Account.class), 8);

* 查询多个对象

		QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
		List<Account> list = queryRunner.query("select * from account ",
		new BeanListHandler<Account>(Account.class));

完整实例:/ConnectionC3P0/src/it/cast/DBUtils/DBUtilsDemo.java

public class DBUtilsDemo {
	@Test
	public void testDBUtils01() throws SQLException {
		//使用c3p0获取datasource
		ComboPooledDataSource dataSource=new ComboPooledDataSource();
		QueryRunner queryRunner=new QueryRunner(dataSource);
		
		//增加
//		queryRunner.update("insert into account values(null,?,?)", "sanlu",1000);
		
		//删除
//		queryRunner.update("delete from account where(id=?)", 11);
		
		//更新
//		queryRunner.update("update account set mony = ? where id =?", 10000,5);
		
		//查询
		//查询到的数据还是在Result里边,然后调用handle()方法,由用户手动封装。
		/*Account account = queryRunner.query("select * from account where id = ?", new ResultSetHandler<Account>() {

			@Override
			public Account handle(ResultSet rs) throws SQLException {
				Account account=new Account();
				while(rs.next()) {
					String name = rs.getString("name");
					int mony = rs.getInt("mony");
					
					account.setMony(mony);
					account.setName(name);
				}
				return account;
			}
		}, 1);
		System.out.println(account.toString());
		*/
		
		//查单个对象
		/*Account account = queryRunner.query("select * from account where id = ?",
				new BeanHandler<Account>(Account.class), 6);
		System.out.println(account.toString());
		*/
		//查询多个对象
		List<Account> list = queryRunner.query("select * from account", new BeanListHandler<Account>(Account.class));
		for (Account account : list) {
			System.out.println(account.toString());
		}
	}
}

装查询结果数据的对象:Account

public class Account {
	
	private String name=null;
	private int mony=0;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getMony() {
		return mony;
	}
	public void setMony(int mony) {
		this.mony = mony;
	}
	@Override
	public String toString() {
		return "Account [name=" + name + ", mony=" + mony + "]";
	}
	
}

ResultSetHandler 常用的实现类

以下两个是使用频率最高的

    BeanHandler,  查询到的单个数据封装成一个对象
    BeanListHandler, 查询到的多个数据封装 成一个List<对象>


    ArrayHandler,  查询到的单个数据封装成一个数组
    ArrayListHandler,  查询到的多个数据封装成一个集合 ,集合里面的元素是数组。 

  
    MapHandler,  查询到的单个数据封装成一个map
    MapListHandler,查询到的多个数据封装成一个集合 ,集合里面的元素是map。 


ColumnListHandler
KeyedHandler
ScalarHandler



                                                     自定义DButils

元参数:Meata data 

描述数据的数据 String sql , 描述这份sql字符串的数据叫做元数据

    数据库元数据 : DatabaseMetaData
    参数元数据  :ParameterMetaData(用的比较多)
    结果集元数据  :ResultSetMetaData

bean类:ConnectionC3P0/src/it/cast/domain/Account.java

/**
 * 装查询结果数据的对象
 */
public class Account {
	
	private String name=null;
	private int mony=0;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getMony() {
		return mony;
	}
	public void setMony(int mony) {
		this.mony = mony;
	}
	@Override
	public String toString() {
		return "Account [name=" + name + ", mony=" + mony + "]";
	}
}

定义查询结果数据封装的规则:ResultSetHandler

public interface ResultSetHandler <T> {
	//自定义处理数据的handle函数
	T handle(ResultSet rs);
}

增删改查:ConnectionC3P0/src/commoncrud/CommonCRUDUtil.java

public class CommonCRUDUtil {
	
	@Test
	public void testQuery() {
		
		query("select * from account where id = ?", new ResultSetHandler<Account>() {

			@Override
			public Account handle(ResultSet rs) {
				Account account=new Account();
				try {
					while (rs.next()) {
						String name = rs.getString("name");
						int mony = rs.getInt("mony");
						account.setMony(mony);
						account.setName(name);
						System.out.println(account.toString());
					}
				} catch (SQLException e) {
					e.printStackTrace();
				}
				return null;
			}
		}, 1);
	}
	
	/**
	 * @param sql :要处理的sql语句
	 * @param handler :自定义的用户处理查询结果集的对象
	 * @param args :可变参数,有几个传几个
	 * @return :返回查询结果
	 */
	public <T>T query(String sql,ResultSetHandler<T> handler, Object...args) {
		
		Connection conn =null;
		PreparedStatement ps =null;
		ResultSet rs=null;
		try {
			conn = JDBCUtil.jdbcConn();
			ps = conn.prepareStatement(sql);
			//获取有几个占位符(?)
			ParameterMetaData metaData = ps.getParameterMetaData();
			int count = metaData.getParameterCount();
			for (int i = 0; i < count; i++) {
				ps.setObject(i+1, args[i]);
			}
			//执行查询
			rs = ps.executeQuery();
			//返回结果集,让用户去处理数据
			T t=(T)handler.handle(rs);
			return t;
			
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCUtil.resease(rs, ps, conn);
		}
		return null;
	}
	
	
	
	/**********************************************************/
	@Test
	public void testUpdate() {
		//增
//		update2("insert into account values(null,?,?)","zhangsan",10086,6,8,254);
		//删
//		update2("delete from account where id = ?", 9);
		//改
		update2("update account set mony = ? where id = ?", 99999,5);
		
	}
	
	/**
	 * 使用数组进行遍历
	 * @param sql sql需要操作的sql语句
	 * @param args 可变参数,有几个占位符就写几个参数
	 */
	public void update1(String sql,Object...args) {
		Connection conn =null;
		PreparedStatement ps =null;
		try {
			conn = JDBCUtil.jdbcConn();
			ps = conn.prepareStatement(sql);
			for (int i = 0; i < args.length; i++) {
				ps.setObject(i+1, args[i]);
			}
			ps.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCUtil.resease(ps, conn);
		}
	}
	/**
	    * 使用?的个数进行循环
	 * @param sql需要操作的sql语句
	 * @param args 可变参数,有几个占位符就写几个参数
	 */
	public void update2(String sql,Object...args) {
		Connection conn =null;
		PreparedStatement ps =null;
		try {
			conn = JDBCUtil.jdbcConn();
			ps = conn.prepareStatement(sql);
			//获取元参数对象
			ParameterMetaData metaData = ps.getParameterMetaData();
			int count = metaData.getParameterCount();
			for (int i = 0; i < count; i++) {
				ps.setObject(i+1, args[i]);
			}
			ps.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCUtil.resease(ps, conn);
		}
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值