JDBC
接口
标准 规范
解耦,,符合开闭原则 扩展和维护
复杂的应用逻辑抽象成接口
Connection,Driver…都是接口,为什么?
JDBC介绍
JAVA Database Connectivity------- java 数据库连接
JDBC是一种用于执行sql语句的java API,是java应用连接各种关系型数据库的基本的接口,可以为多种关系数据库提供统一访问。
SUN公司提供的一种数据库访问规则、规范(接口),数据库厂商编写具体实现,下载jar包即驱动程序(对接口实现类的jar文件)。
/**
* 数据库
*
* IP : port
* jdbc:mysql 协议,连接数据库的类型
*
*
* 1.下载jar拷贝到lib下
* 2. 声明 url driver username password
* 3. 代码:加载驱动 DriverManager创建连接 -> 创建Statment -> 执行SQL ->--关闭连接释放资源
* 建议:先测试连接 ,注意:driver类拼写问题,IP和端口问题
*
*
* Statement:
* 特殊字符问题
* 注入安全问题
* 执行效率问题
*/
driver:驱动 Driver.class下
url:协议(jdbc:mysql://)+ip地址+端口+数据库名
username
password
package util;
public class JdbcUtil {
private static String driver = "com.mysql.cj.jdbc.Driver";//类
private static String url = "jdbc:mysql://127.0.0.1:3306/testdb?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT";
private static String username = "root";
private static String password = "root";
public static Connection getConn(){
Connection conn = null;
try {
Class.forName(driver);
conn = DriverManager.getConnection(url, username, password);
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
public static void release(Connection conn , PreparedStatement pst , ResultSet rst){
closeRst(rst);
closePst(pst);
closeConn(conn);
}
private static void closeRst(ResultSet rst){
try {
if(rst != null){
rst.close();
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
rst = null;
}
}
private static void closePst(PreparedStatement pst){
try {
if(pst != null){
pst.close();
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
pst = null;
}
}
private static void closeConn(Connection conn){
try {
if(conn != null){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
conn = null;
}
}
}
//结果集元数据
public static List<User> queryAll2() {
String sql2 = "select * from users";
Connection conn = JdbcUtil.getConn();
PreparedStatement pst;
try {
pst = conn.prepareStatement(sql2);
// ResultSet rs = pst.executeQuery();
ResultSetMetaData rsmd = pst.getMetaData();
// ResultSetMetaData rsmd = rst.getMetaData();
//列数,与sql语句有关
int count = rsmd.getColumnCount();
System.out.println(count);
for (int i = 0; i <count; i++) {
// String colsName = rsmd.getColumnLabel(i+1);//真实表中的名称
String labelName = rsmd.getColumnName(i+1);//别名 as xxx
int type = rsmd.getColumnType(i+1);
String typeStr = rsmd.getColumnTypeName(i+1);
System.out.println(typeStr+"-----"+labelName);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
/**
* 结果集元数据
*/
public static void metaData() {
// String sql = "select sid,tel as phone from student"; //注意别名问题
String sql = "select * from student";
Connection conn =ConnectionUtil.getConnection();
try {
PreparedStatement pst = conn.prepareStatement(sql);
// ResultSet rst = pst.executeQuery();
ResultSetMetaData meta = pst.getMetaData();
// ResultSetMetaData meta = rst.getMetaData();
//列数
int count = meta.getColumnCount();
for (int i = 0; i < count; i++) {
String colsName = meta.getColumnName(i+1);
String labelName = meta.getColumnLabel(i+1);
int type = meta.getColumnType(i+1);
String typeStr = meta.getColumnTypeName(i+1);
System.out.println(type+"===="+typeStr);
// System.out.println(colsName+"==="+labelName);
}
// System.out.println(count);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Statement问题:(sql语句用字符串拼接,先拼接再执行)
sql 注入安全问题:登录问题
执行效率低下:多次执行情况下
特殊字符处理问题:‘ 、%
/**
* Statement版本
*/
public class DataBase1 {
private static String driver = "com.mysql.cj.jdbc.Driver";//类
private static String url = "jdbc:mysql://127.0.0.1:3306/testdb?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT";
private static String username = "root";
private static String password = "root";
//增删改操作
public static void insert() throws Exception {
//加载驱动
Class.forName(driver); //static{} 类加载时执行
//创建连接
Connection conn = DriverManager.getConnection(url,username, password);
System.out.println(">>>"+conn);
//创建statement声明,用来发sql
Statement st = conn.createStatement();
//发出SQL指令,执行
String sql = "insert into users(username,password,email) values('赵晴','nihao','233888@163.com')";
int rows = st.executeUpdate(sql);
System.out.println(">>>受影响的行数:"+rows);
//关闭连接
st.close();
conn.close();
}
public static void update() throws Exception {
//加载驱动
Class.forName(driver); //static{} 类加载时执行
//创建连接
Connection conn = DriverManager.getConnection(url,username, password);
System.out.println(">>>"+conn);
//创建statement声明
Statement st = conn.createStatement();
//发出SQL指令
String sql = "update users set password = 'wss' where username='赵晴'";
int rows = st.executeUpdate(sql);
System.out.println(">>>受影响的行数:"+rows);
//关闭连接
st.close();
conn.close();
}
public static void delete() throws Exception {
//加载驱动
Class.forName(driver); //static{} 类加载时执行
//创建连接
Connection conn = DriverManager.getConnection(url,username, password);
System.out.println(">>>"+conn);
//创建statement声明,用来发sql
Statement st = conn.createStatement();
//发出SQL指令,执行
String sql = "delete from users where username='赵晴'";
int rows = st.executeUpdate(sql);
System.out.println(">>>受影响的行数:"+rows);
//关闭连接
st.close();
conn.close();
}
//查询操作
public static void query() throws Exception {
Connection conn = null;
Statement st = null;
ResultSet rst = null;
try {
//加载驱动
Class.forName(driver); //static{} 类加载时执行
//创建连接
conn = DriverManager.getConnection(url,username, password);
System.out.println(">>>"+conn);
//创建statement声明,用来发sql
st = conn.createStatement();
//发出SQL指令,执行
String sql = "select * from users";
rst = st.executeQuery(sql);
System.out.println("------------");
//boolean is = rst.next();//鼠标下移,指向下一条记录,若查到为true,否则false
while(rst.next()){
//注意:列的位置从1开始,不是0
//String name = rst.getString(0);
String name = rst.getString("username");
String pwd = rst.getString("password");
String email = rst.getString("email");
System.out.println("["+name + ", "+pwd+", "+email+"]");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭连接
if(rst != null) {
rst.close();
}
if(st != null) {
st.close();
}
if(conn != null) {
conn.close();
}
}
}
public static void main(String[] args) {
try {
query();
// insert();
// update();
// delete();
} catch (Exception e) {
e.printStackTrace();
}
}
}
PreparedStatement
/**
* PreparedStatement
*
*/
public class DataBase2 {
private static String driver = "com.mysql.cj.jdbc.Driver";//类
private static String url = "jdbc:mysql://127.0.0.1:3306/testdb?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT";
private static String username = "root";
private static String password = "root";
//增删改操作
public static void insert(String uname,String pwd,String uemail) throws Exception {
//加载驱动
Class.forName(driver); //static{} 类加载时执行
//创建连接
Connection conn = DriverManager.getConnection(url,username, password);
System.out.println(">>>"+conn);
//创建statement声明,用来发sql
String sql = "insert into users(username,password,email) values(?,?,?)";
PreparedStatement pst = conn.prepareStatement(sql);
pst.setString(1, uname);
pst.setString(2, pwd);
pst.setString(3, uemail);
//发出SQL指令,执行
int rows = pst.executeUpdate();
System.out.println(">>>受影响的行数:"+rows);
//关闭连接
pst.close();
conn.close();
}
public static void update(String pwd) throws Exception {
//加载驱动
Class.forName(driver); //static{} 类加载时执行
//创建连接
Connection conn = DriverManager.getConnection(url,username, password);
System.out.println(">>>"+conn);
//创建statement声明
String sql = "update users set password = ? where username='赵晴'";
PreparedStatement pst = conn.prepareStatement(sql);
pst.setString(1, pwd);
//发出SQL指令
int rows = pst.executeUpdate();
System.out.println(">>>受影响的行数:"+rows);
//关闭连接
pst.close();
conn.close();
}
public static void delete(String uname) throws Exception {
//加载驱动
Class.forName(driver); //static{} 类加载时执行
//创建连接
Connection conn = DriverManager.getConnection(url,username, password);
System.out.println(">>>"+conn);
//创建statement声明,用来发sql
String sql = "delete from users where username=?";
PreparedStatement pst = conn.prepareStatement(sql);
pst.setString(1, uname);
//发出SQL指令,执行
int rows = pst.executeUpdate();
System.out.println(">>>受影响的行数:"+rows);
//关闭连接
pst.close();
conn.close();
}
//查询操作
public static void query() {
Connection conn = null;
PreparedStatement pst = null;
ResultSet rst = null;
try {
//加载驱动
Class.forName(driver); //static{} 类加载时执行
//创建连接
conn = DriverManager.getConnection(url,username, password);
System.out.println(">>>"+conn);
//创建statement声明,用来发sql
String sql = "select * from users";
pst = conn.prepareStatement(sql);
//发出SQL指令,执行
rst = pst.executeQuery();
System.out.println("------------");
//boolean is = rst.next();//鼠标下移,指向下一条记录,若查到为true,否则false
while(rst.next()){
//注意:列的位置从1开始,不是0
// String name = rst.getString(0);
String name = rst.getString("username");
String pwd = rst.getString("password");
String email = rst.getString("email");
System.out.println("["+name + ", "+pwd+", "+email+"]");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭连接
try {
if(rst != null) {
rst.close();
}
if(pst != null) {
pst.close();
}
if(conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//登录验证
public static boolean login(String uname, String pwd) {
Connection conn = null;
PreparedStatement pst = null;
ResultSet rst = null;
try {
//加载驱动
Class.forName(driver); //static{} 类加载时执行
//创建连接
conn = DriverManager.getConnection(url,username, password);
System.out.println(">>>"+conn);
//创建声明
String sql = "select * from users where username = ? and password = ?";
pst = conn.prepareStatement(sql);//有sql
//给占位符赋值
pst.setString(1, uname);
pst.setString(2, pwd);
//执行
rst = pst.executeQuery();//无参数
return rst.next();
// if(rst.next()){
// System.out.println("登录成功");
// }else{
// System.out.println("登录失败");
// }
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭连接
try {
if(rst != null) {
rst.close();
}
if(pst != null) {
pst.close();
}
if(conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return false;
}
public static void main(String[] args) {
try {
// query();
insert("雪诺","xniii","zj@127.com");
// update("bvfdde");
// delete("思思");
// login("思思", "123");
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用JDBC完成增删改查的步骤?
加载JDBC驱动 (用反射的方式加载Driver(驱动)类)
连接数据库(通过驱动管理器获取数据库连接(“url”,“name”,“pwd”))
创建PreparedStatement,将sql语句执行到数据库
执行SQL语句,如果是查询返回结果集
关闭连接释放资源
Statment和Prestament的区别及注意点总结。
关系:PreparedStatement继承自Statement,都是接口
区别:PreparedStatement可以使用占位符,是预编译的,批处理比Statement效率高
-
Statement:
定义statemen 语句-》
编写sql语句-》
执行executeUpdate(sql)。
举例:尽量使用preparestatement,使用preparestatement可有效防止sql注入
-
preparestatement:
–》编写sql语句(可能存在占位符?)
–》在创建preparestatement对象是,将sql预编译:preparestatement(sql)
–》执行executeUpdate()<这里括号里不要填写sql,应为已经预编译过了>
–》用setXXX()语句替换占位符。
特殊字符问题:statement中的sql语句,是将参数用字符串拼接在一起,容易出现错误;preparedStatement语句,将参数用占位符代替。
注入安全问题:由于statement语句是将参数作为字符串拼接在sql语句中,如果有人恶意使用拼接,就有可能直接进入数据库,去操作数据。例如: 在sql语句的后面加上 “or 1=1”,有可能就可以获取所有的权限,不安全。
执行效率问题:PreparedStatement尽最大可能提高性能.语句在被DB的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中就会得到执行.这并不是说只有一个Connection中多次执行的预编译语句被缓存,而是对于整个DB中,只要预编译的语句语法和缓存中匹配.那么在任何时候就可以不需要再次编译而可以直接执行;statement的语句中,即使是相同一操作,而由于每次操作的数据不同所以使整个语句相匹配的机会极小,几乎不太可能匹配,并不是所以预编译语句都一定会被缓存,数据库本身会用一种策略,比如使用频度等因素来决定什么时候不再缓存已有的预编译结果.以保存有更多的空间存储新的预编译语句.
写一个完成的UserDao,里面包含用户添加,修改,删除,查询全部,登录,检查重名,根据主键查询用户方法。 并运行调用,测试通过!
BaseDao.java
package util;
/**
* 工具类,封装
*/
public class BaseDao {
protected static String driver = "com.mysql.cj.jdbc.Driver";
protected static String url = "jdbc:mysql://127.0.0.1:3306/testdb?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT";
protected static String username = "root";
protected static String password = "root";
protected Connection conn; //不设置为static的
protected PreparedStatement pst;
protected ResultSet rst;
/**
* 查询
* 封装一个通用工具,只传入sql即可
*
* @param sql
* @param param
* @return
*/
public ResultSet query(String sql , Object...param) { //可变参数======处理占位符?的个数
//System.out.println("》》》打印sql:"+sql);
//System.out.println("》》》打印param:"+Arrays.toString(param));
conn=getConn();
try {
pst=conn.prepareStatement(sql);
//给占位符赋值
if(param != null) {
for (int i = 0; i < param.length; i++) {
pst.setObject(i+1,param[i]);//自动判断类型
}
}
rst=pst.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
} finally {
//close();
}
return rst;
}
/**
* ResultSet --> List<T>
* @param sql
* @param params
* @return
*/
public <T> List<T> queryList(Class<T> clazz , String sql , Object[] params){
//获取结果集
rst = query(sql, params);
List<T> list = new ArrayList<T>();
try {
while(rst.next()) {
//根据sql语句查询的列数,取出给对象
//获取元数据
ResultSetMetaData rsmd = rst.getMetaData();
//获得列数
int colsCount = rsmd.getColumnCount();
//实例化对象
T obj = clazz.newInstance();
list.add(obj);
//对一个对象所有属性的封装,与查询的列对应
for (int i = 0; i < colsCount; i++) {//循环一次完成一列的取值以及给对象属性附一个值
String colsName = rsmd.getColumnLabel(i+1);//列名
Object value = rst.getObject(colsName);
//反射
String methodName = "set"+colsName.substring(0,1).toUpperCase()+colsName.substring(1);
//属性类型获取操作---属性类型
Field field;
try {
field = obj.getClass().getDeclaredField(colsName);
Class<?> type = field.getType();
//反射出方法对象Method ---- 方法的执行,是"对象"的方法的执行
Method method = obj.getClass().getDeclaredMethod(methodName,type);
method.invoke(obj, value);
} catch (NoSuchFieldException | SecurityException | NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
} finally {
close();
}
}
//list.add(obj);
}
} catch (SQLException e) {
e.printStackTrace();
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
} finally {
close();
}
return null;
}
/**
* 更新
*
* @param sql
* @param param
* @return
*/
public int update(String sql , Object...param) {
conn = getConn();
try {
pst=conn.prepareStatement(sql);
if(param != null) {
for (int i = 0; i < param.length; i++) {
pst.setObject(i+1,param[i]);
}
}
int rows = pst.executeUpdate();
return rows;
} catch (SQLException e) {
e.printStackTrace();
}
return -1;
}
/**
* 连接
* @return
*/
public Connection getConn() {
try {
if((conn == null)|| conn.isClosed()) {// conn为null/关闭时重新加载驱动,防止多次连接
Class.forName(driver);
conn = DriverManager.getConnection(url, username, password);
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return conn;
}
/**
* 关闭连接
*/
public void close() {
try {
rst.close();
rst = null;
} catch (SQLException e) {
e.printStackTrace();
}
try {
pst.close();
pst = null;
} catch (SQLException e) {
e.printStackTrace();
}
try {
conn.close();
conn = null;
} catch (SQLException e) {
e.printStackTrace();
}
}
}
UserDao.java
public class UserDao extends BaseDao{
public List<User> queryAll(){
String sql = "select * from users";
rst = query(sql);
//ResultSet--->List
return null;
}
public List<User> queryAll(String name,String pwd){
String sql = "select * from users where username=? and password=?";
Object[] param = {name,pwd};
rst = query(sql,param);
// rst = query(sql,name,pwd);
try {
while(rst.next()) {
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close();
}
return null;
}
public boolean update(String uname,String pwd,String uemai) {
String sql = "";
Object[] param = {};
return super.update(sql, param)>0;
}
public boolean save(User user) {
String sql = "";
Object[] param = {user.getUsername(),user.getPassword()};
return super.update(sql, param)>0;
}
public boolean delete(int id) {
String sql = "";
return super.update(sql, id) > 0 ;
}
}
现有一个List list中有100000条记录,然后编写一个方法 addBatch(List){} 完成100000条记录的添加。(预处理或批处理实现,对比性能)
public class TestBatch {
private static List<Account> list;
static {
//此处模拟多条记录的数据来源 千百万的记录数据 移动----短信 ----excel--导入---mysql---Statement---10w---1~2小时---2分钟
list = new ArrayList<Account>();
for (int i = 0; i < 100000; i++) {
Account account = new Account("A"+i,"111111",i%10000);
list.add(account);
}
}
/**
* 要执行批量处理,注意:关闭自动提交功能 开启事务
* 一百万条总耗时:155034
*/
public static void batchAdd(List<Account> list) {
Connection conn = null;
PreparedStatement pst = null;
try {
conn = ConnectionUtil.getConnection();
String sql = "INSERT INTO ACCOUNT(ACCNAME,PASSWORD,BALANCE,ACCDATE)VALUES(?,?,?,NOW())";
//预处理-------------------
pst = conn.prepareStatement(sql);
//事务 默认自动提交事务
conn.setAutoCommit(false);// 自动提交关闭
int i = 0;
for (Account account:list) {
pst.setString(1, account.getAccname());
pst.setString(2, account.getPassword());
pst.setFloat(3,account.getBalance());
//添加到批处理队列 缓存
pst.addBatch();
if(++i%6000==0){
pst.executeBatch();//执行批处理
//提交事务
conn.commit();
pst.clearBatch();
}
}
//1000000万=====
pst.executeBatch();//执行批处理
//提交事务
conn.commit();
} catch (Exception e) {
e.printStackTrace();
try {
conn.rollback();//事务回滚
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally {
ConnectionUtil.close(conn, pst, null);
}
}
/**
* 测试
*/
public static void main(String[] args) {
System.out.println(">>>==开始导入....");
long start = System.currentTimeMillis();
batchAdd(list);
long end = System.currentTimeMillis();
System.out.println("总耗时:"+(end-start));
}
}
批量删除,编写deleteAll(List userid); 实现批量删除上万条记录
数据库(2)
面试时回答事务概念和特性即可。
事务:要么全部执行,要么全部都不执行。
数据库事务四大特性是什么?-----ACID
1、原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
2、 一致性(Consistency)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
3、隔离性(Isolation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
4、持久性(Durability)
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
/**
* 事务:
* 要么全部都执行,要么全部都不执行。
* 一致性 持久性 隔离性 原子性
*/
public class TestTrans {
public static void main(String[] args) {
test2();
}
/**
* account 表
* zhang 1000
* wang 0
* zhang给wang转账500元
*
*/
public static void test1() {
Connection conn = ConnectionUtil.getConnection();
PreparedStatement pst = null;
try {
pst = conn.prepareStatement("update account set balance=balance+? where accname=?");
pst.setInt(1, -500);
pst.setString(2, "zhang");
pst.executeUpdate(); ///执行
System.out.println("-------------给wang+500---------------------");
pst.setInt(1, 500);
pst.setString(2, "wang");
pst.executeUpdate(); ///执行
System.out.println("=======转账成功!=====");
} catch (SQLException e) {
e.printStackTrace();
}finally {
ConnectionUtil.close(conn, pst, null);
}
}
/**
* 加上事务控制
*/
public static void test2() {
Connection conn = ConnectionUtil.getConnection();
PreparedStatement pst = null;
try {
//设置 不自动提交事务
conn.setAutoCommit(false);
pst = conn.prepareStatement("update account set balance=balance+? where accname=?");
pst.setInt(1, -500);
pst.setString(2, "zhang");
pst.executeUpdate(); ///执行
System.out.println("-------------给wang+500---------------------");
pst.setInt(3, 500);
pst.setString(2, "wang");
pst.executeUpdate(); ///执行
conn.commit();//提交事务
System.out.println("=======转账成功!=====");
} catch (SQLException e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
//
e1.printStackTrace();
}//回滚事务
}finally {
ConnectionUtil.close(conn, pst, null);
}
}
}
//**
// * 事务 要么全部都执行 要么全部都不执行
// * 原子性 持久性 一致性 隔离性
// *
// */
//public class TestTran {
//
// public static void main(String[] args) {
tran1();
// trans();
// }
// /**
// * 下面模拟如果没有事务控制,转账过程中的风险问题
// * 假设zhang 原有余额 1000 wang 原有余额 0 那么:
// * 如果 zhang成功转出500 则结果应该为 zhang余额500 wang 余额500
// * 如果zhang转出500失败则结果应该为zhang余额1000 wang余额0 这样才对,
// * 但是因为没有事务控制,所以在中间出现异常时,结果却是zhang余额变为500 wang还是0 ,造成了结果不一致。
// */
// public static void tran1() {
// ConnectionUtil connUtil = new ConnectionUtil();
// Connection conn = new ConnectionUtil().getConnection();
// PreparedStatement pst = null;
// try {
// //转账 修改语句
// String sql = "UPDATE ACCOUNT SET BALANCE=BALANCE+? WHERE ACCNAME=?";
// pst = conn.prepareStatement(sql);
//
// //给 zhang 账户减去500
// pst.setFloat(1, -500);
// pst.setString(2, "zhang");
// pst.executeUpdate();
//
// "".substring(444);//引发异常
//
// //给 wang 账户加上500
// pst.setFloat(1, 500);
// pst.setString(2, "wang");
// pst.executeUpdate();
//
// System.out.println("转账成功!");
// } catch (Exception e) {
// System.out.println("转账失败!");
// e.printStackTrace();
// }finally {
// connUtil.close(conn, pst, null);
// }
// }
// /**
// * 下面案例使用了事务控制,定义了事务边界,把两个修改作为不可分割的单元,即原子性特点
// * 两个修改如果都成功则提交事务。否则一个异常失败,则回滚事务,保证数据一致性
// */
//
// public static void trans() {
// ConnectionUtil connUtil = new ConnectionUtil();
// Connection conn = new ConnectionUtil().getConnection();
// PreparedStatement pst = null;
// try {
// //关闭自动提交 -----在执行更新前
// conn.setAutoCommit(false);
//
// //转账 修改语句
// String sql = "UPDATE ACCOUNT SET BALANCE=BALANCE+? WHERE ACCNAME=?";
// pst = conn.prepareStatement(sql);
//
// //给 zhang 账户减去500
// pst.setFloat(1, -500);
// pst.setString(2, "zhang");
// pst.executeUpdate();
//
// "".substring(444);//引发异常
//
// //给 wang 账户加上500
// pst.setFloat(1, 500);
// pst.setString(2, "wang");
// pst.executeUpdate();
//
// //提交事务---
// conn.commit();
// System.out.println("转账成功!");
// } catch (Exception e) {
// System.out.println("转账失败!");
// //事务回滚
// try {
// conn.rollback();
// } catch (SQLException e1) {
// e1.printStackTrace();
// }
// }finally {
// connUtil.close(conn, pst, null);
// }
// }
//
//
//}
数据库组件:(数据库增删改查)
DBUtils
/**
* 本类演示使用dbutils的数据插入,更新和删除
*
*/
public class TestDbUtils {
public static void main(String[] args) {
insert2();
// insert1();
}
/**
* 插入操作并返回记录主键
* 使用update方法,可以执行 insert,update,delete。返回的结果都为影响的行数
*/
public static void insert2() {
//获取连接
Connection conn = ConnectionUtil.getConnection();
//创建QueryRunner对象
QueryRunner qr = new QueryRunner();
//下面sql分别为插入,修改,删除,可以分别选一种演示
// String sql = "INSERT INTO ACCOUNT(ACCNAME,PASSWORD,BALANCE,STATE)VALUES(?,?,?,?)";
// String sql = "UPDATE ACCOUNT SET PASSWORD=? WHERE ACCID IN(?,?)";
String sql = "DELETE FROM ACCOUNT WHERE ACCID=?";
//给占位符赋值的参数列表
// Object[] params = {"zhangsan","222222",2000,0};
// Object[] params = {"123456",1,2};//修改的参数
Object[] params = {2}; //删除的参数
try {
//执行插入并返回影响的行数
int rows = qr.update(conn, sql, params);
System.out.println(">>>>影响的行数=="+rows);
} catch (SQLException e) {
e.printStackTrace();
}finally {
ConnectionUtil.close(conn, null, null);
}
}
/**
* 插入操作并返回记录主键
* 如果插入记录时,还需要获取插入的记录的主键 ,可以使用下面的insert()方法
*/
public static void insert1() {
ConnectionUtil connUtil = new ConnectionUtil();
//获取连接
Connection conn = connUtil.getConnection();
//创建QueryRunner对象
QueryRunner qr = new QueryRunner();
String sql = "INSERT INTO ACCOUNT(ACCNAME,PASSWORD,BALANCE,STATE)VALUES(?,?,?,?)";
//给占位符赋值的参数列表
Object[] params = {"wang","123456",1000,1};
//Account表主键为自动增长,使用ScalarHandler可以在执行insert后获取生成主键
ScalarHandler<Long> handler = new ScalarHandler<Long>();
try {
//执行插入并返回主键
Long id = qr.insert(conn,sql, handler, params);
System.out.println(">>>>主键=="+id);
} catch (SQLException e) {
e.printStackTrace();
}finally {
connUtil.close(conn, null, null);
}
}
}
/**
* 本类演示使用dbutils 查询操作,这是最常用和方便的方式
*
*/
public class TestDBUtilsQuery {
public static void main(String[] args) {
// queryOne();
queryAll();
}
/**
* 查询多个对象需要BeanHandler
*/
public static void queryAll() {
// ConnectionUtil connUtil = new ConnectionUtil();
// 获取连接
Connection conn = ConnectionUtil.getConnection();
// 创建QueryRunner对象
QueryRunner qr = new QueryRunner();
//查询语句 注意,查询的字段名一定要属性名一致,否则属性值不能自动封装到对象中。如果不一致可以使用as 取别名
String sql = "select accid,accname,password,balance,accDate from account";
//实例化Handler,指定了封装的实体类
BeanListHandler<Account> rsh = new BeanListHandler<Account>(Account.class);
try {
List<Account> accounts = qr.query(conn, sql, rsh);
//循环查看结果
for (Account account : accounts) {
System.out.println(account.getAccid()+"=="+account.getAccname()+"=="+account.getBalance());
}
} catch (SQLException e) {
e.printStackTrace();
}finally {//这里就可以直接关闭了,因为已经不再使用ResultSet,不需要保持连接了
ConnectionUtil.close(conn, null, null);
}
}
/**
* 查询一个对象需要BeanHandler
*/
public static void queryOne() {
// 获取连接
Connection conn = ConnectionUtil.getConnection();
// 创建QueryRunner对象
QueryRunner qr = new QueryRunner();
//查询语句 注意,查询的字段名一定要属性名一致,否则属性值不能自动封装到对象中。如果不一致可以使用as 取别名
String sql = "select accid,accname,password,balance,accDate from account where accid=?";
//实例化Handler,指定了封装的实体类
BeanHandler<Account> rsh = new BeanHandler<Account>(Account.class);
try {
// qr.query(conn, sql, rsh, 3);
Account account = qr.query(conn, sql, rsh);
System.out.println(account.getAccname()+"===="+account.getPassword());
} catch (SQLException e) {
e.printStackTrace();
}finally {//这里就可以直接关闭了,因为已经不再使用ResultSet,不需要保持连接了
ConnectionUtil.close(conn, null, null);
}
}
}
数据库连接池:(管理连接)
dhcp(不用):底层是装饰者模式
**c3p0:**底层是动态代理
池类ComboPooledDataSource
c3p0-config.xml文件,放在src下
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- 默认配置,当使用ComboPooledDataSource无参构造器时,使用的就是这个配置 -->
<default-config>
<!-- 基本配置 -->
<property name="jdbcUrl">jdbc:mysql://localhost:3306/bank</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 每次增量,当需要创建Connection对象时,一次创建几个 -->
<property name="acquireIncrement">3</property>
<!-- 当创建池对象后,池中应该有几个Connection对象 -->
<property name="initialPoolSize">3</property>
<!-- 池中最少Connection个数,如果少于这个值,就会创建Connection -->
<property name="minPoolSize">2</property>
<!-- 池中最大连接个数 -->
<property name="maxPoolSize">10</property>
</default-config>
<!-- 命名配置,new ComboPooledDataSource("oralce-config")时,使用的就是这个配置 -->
<named-config name="oracle-config">
<property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="user">root</property>
<property name="password">123</property>
<property name="acquireIncrement">3</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">2</property>
<property name="maxPoolSize">10</property>
</named-config>
</c3p0-config>
import java.sql.Connection;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class Test1 {
public static void main(String[] args) {
ComboPooledDataSource ds = new ComboPooledDataSource();
try {
for (int i = 0; i < 10; i++) {
Connection conn1 = ds.getConnection();
System.out.println(i+">>>>===="+conn1);
// conn1.close(); ///释放到连接池中
// conn2.close(); ///释放到连接池中
// conn3.close(); ///释放到连接池中
Thread.sleep(500);
if(i%2==0) {
conn1.close();
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}