1.dbutils包:
提供执行sql语句的功能,简化过程
(1)执行添加、删除语句
public static void add() throws SQLException { QueryRunner qr = new QueryRunner();//实例化 Connection conn = DButil.getConn();//获取数据库连接 String sql = "insert into userscount(uname,upwd) values(?,?)"; Object[] obj = {"god","123456"}; int pow = qr.update(conn, sql,obj);//传入链接对象,sql语句,obj对象,obj数组内的两个值对应两个预留字符 conn.close(); if(pow>0) { System.out.println("添加成功!"); }else { System.out.println("添加失败!"); } }
public static void delete() throws SQLException { QueryRunner qr = new QueryRunner(); Connection conn = DButil.getConn(); String sql = "delete from userscount where uid=?"; int pow = qr.update(conn,sql,1);//可以直接传入多个参数来对应预留字符 conn.close(); if(pow>0) { System.out.println("删除成功!"); }else { System.out.println("删除失败!"); } }
增删改都调用update()方法。
(2)查询
查询调用query()方法,最常用的是将查询的结果存入javabean对象中,然后把多个结果存入集合中
public static void findBeanList() throws SQLException { QueryRunner qr = new QueryRunner(); Connection conn = DButil.getConn(); String sql = "select * from userscount"; List<UserBean> list = qr.query(conn, sql,new BeanListHandler<UserBean>(UserBean.class)); //查询到的每条记录存入对象中,对象存入list中 for(UserBean b:list) { System.out.println(b.getUid()+"::"+b.getUname()+"::"+b.getUpwd()); } conn.close(); }
其他的查询方法:
public static void find() throws SQLException { QueryRunner qr = new QueryRunner(); Connection conn = DButil.getConn(); String sql = "select * from userscount"; Object[] obj = qr.query(conn,sql, new ArrayHandler());//查询到的第一条记录存入集合 for(Object o:obj) { System.out.println(o); } conn.close(); }
public static void findList() throws SQLException { QueryRunner qr = new QueryRunner(); Connection conn = DButil.getConn(); String sql = "select * from userscount"; List<Object[]> list = qr.query(conn,sql, new ArrayListHandler());//查询到的每条记录记录存入Object数组然后放入Arraylist中 for(Object[] o:list) { for(Object obj:o) { System.out.println(obj); } } conn.close(); }
public static void findBean() throws SQLException { QueryRunner qr = new QueryRunner(); Connection conn = DButil.getConn(); String sql = "select * from userscount"; UserBean ub = qr.query(conn, sql,new BeanHandler<UserBean>(UserBean.class));//查询到的第一条记录存入对象中 conn.close(); }
public static void findScalar() throws SQLException { QueryRunner qr = new QueryRunner(); Connection conn = DButil.getConn(); String sql = "select count(*) from userscount group by uname"; long count = qr.query(conn, sql,new ScalarHandler<Long>());//查找指定数据 System.out.println(count); conn.close(); }
2.连接池(pool、dbcp)
提供DataSource接口(java中提供的连接池)的实现类BasicDataSource,连接数据库并返回一个连接池对象
public class ConnPool { public static DataSource getDataSource() { try(InputStream in = ConnPool.class.getClassLoader().getResourceAsStream("DButil.properties");){ Properties pro = new Properties(); pro.load(in); String driver = pro.getProperty("driver"); String url = pro.getProperty("url"); String user = pro.getProperty("user"); String password = pro.getProperty("password"); BasicDataSource dataSource = new BasicDataSource(); dataSource.setDriverClassName(driver); dataSource.setUrl(url); dataSource.setUsername(user); dataSource.setPassword(password); return dataSource; } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("连接数据库失败!"+e); } } }
如何使用连接池:
将连接池对象传入QueryRunner的构造方法中
public static void findMap() throws SQLException { QueryRunner qr = new QueryRunner(ConnPool.getDataSource());//将连接池对象传入 String sql = "select * from userscount"; Map<String, Object> map = qr.query(sql,new MapHandler());//key是字段名,value是数据 Set<Entry<String,Object>> entry = map.entrySet(); for(Entry<String,Object> e:entry) { System.out.println(e.getKey()+":"+e.getValue()); } }
3.JDBC事务
一般情况下,sql语句在excute后会自动将数据提交到数据库,而使用手动事务后,数据会暂存在事务日志中,可以防止多条语句执行时,其中一条语句执行失败而其他语句成功执行的情况,同时可以回滚数据取消操作。
public class Demo { public static void main(String[] args){ try { Connection conn = DButil.getConn(); String sql1 = "insert into userscount(uname,upwd) values(?,?)"; String sql2 = "insert into userscoun(uname,upwd) values(?,?)";//故意写错,表名少个t //关闭自动提交事务 conn.setAutoCommit(false); PreparedStatement ps1 = conn.prepareStatement(sql1); ps1.setString(1, "admin"); ps1.setString(2, "123456"); ps1.executeUpdate(); PreparedStatement ps2 = conn.prepareStatement(sql2); ps2.setString(1, "user1"); ps2.setString(2, "123456"); ps2.executeUpdate(); // 手动提交事务 conn.commit(); //conn.rollback();回滚数据 //上面两条数据都没有被加入数据库 DButil.close(ps1, conn); } catch (Exception e) { System.out.println("添加数据失败!"); } } }
需要注意的是,手动事务能成功的前提是执行sql语句的statement来自于同一个Connection,一般DAO层的方法是在Service层执行的,所以在Service层的方法中,每个方法内的DAO层方法要使用同一个Connection,将其作为参数传入DAO层的方法:
public void method(){ Connection conn =DButil.getConn(); conn.setAutoCommit(false); 方法(conn,其他参数) ; 方法(conn,其他参数); . . . . conn.commit(); }
利用ThreadLocal改进上述方法:
DButil内改动
private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>(); //获取连接 public static Connection getCurrentConn() throws SQLException { Connection conn = tl.get(); if(conn==null) { tl.set(getConn()); } return conn; } //开启手动事务 public static void startManul() throws SQLException { Connection conn = getCurrentConn(); conn.setAutoCommit(false); } //回滚 public static void manulRollback() throws SQLException { Connection conn = getCurrentConn(); conn.rollback(); } //手动提交 public static void manulCommit() throws SQLException { Connection conn = getCurrentConn(); conn.commit(); }
DAO层方法:
public void method(){ Connection conn =DButil.getCurrentConn(); 业务逻辑.... }
Service层改动:
public void method(){ DButil.startManul(); 方法(参数) ; 方法(参数); . . . . DButil.manulCommit(); }finally{ manulRollback(); }