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();
}
