MyBatis第一课:回忆JDBC

来源:互联网 发布:生姜怎样治疗脱发 知乎 编辑:程序博客网 时间:2024/06/03 09:36

学完SSM很久了,一直想总结一下学到的东西,今天就先写一篇关于JDBC的,作为MyBatis的祭品。

在学习MyBatis之前,我们肯定都用过原生JDBC,不管是MyBatis还是Hibernate,这些ORM框架都是在JDBC的基础之上而进行封装的,我自己就曾经封装过一个JDBCTemplate,不过 功能就差远了。

因此我们先回顾一下原生JDBC:

首先是JDBC的操作步骤,大致如下:

1.加载驱动。

2.配置数据源,创建并获得一条与数据库的连接。

3.创建一个Statement对象。对于MySQL来说,常用的Statement有两种:执行静态语句的Statement和执行动态语句的PrepareStatement。

4.执行sql语句。Statement接口提供了三种执行sql语句的方式:execute(),excuteQuery() 查询,executeUpdate() 增删改 。 参考:三种执行方式的不同

5.操作结果集 。如果执行的是查询操作,则返回查询的结果集;如果执行的是更新(增删改)操作,则返回执行sql语句之后所影响的行数。

6.关闭连接,释放资源。


其中1,2两步我们可以封装在DBUtils中,这个网上随便都能搜到。3456步可以根据自己的方式尽量精简,比如把增删改都是为一种对数据库的更新操作,除了sql语句的不同以及预编译占位符需要填入的参数的不同,增删改确实可以整合在一起。

而查询操作就和更新不同,查询需要resultset来操作结果集,通过获得的resultset取出查询到的结果。

此时遇到一个问题,对于增删改操作,比如方法名就叫update(String sql, Object[] args),进行Statement的操作完成之后,我们可以直接在update方法内关闭连接。

但是,对于查询操作,比如方法名就叫query(String sql, Object[] args),进行查询之后可是要通过resultset来取得结果的,如果你直接把ResultSet作为参数返回,那么又如何获取到当时建立连接时创建的Connection并且关闭呢?那如果我们直接把操作结果集的实体类对象(比如:User对象,Student对象,他们的属性并不相同)作为参数传入query,又怎么动态的改变实体类对象呢?你却是可以动态的改变传入的sql语句来改变你要获取到的结果集,可是你又怎么用User对象/Student对象动态的把结果集设置为他们的属性值并且返回呢?当然,你可以通过更进一步的封装,我有以下几个思路:

1.保持实体类和数据库中字段值的高度一致,通过你查询的列名,用反射的方式,分别设置对象的属性

2.通过异步回调的方式,在update方法中调用回调函数,动态设置对象的属性。

3.......

第一种方法有点麻烦,因此我的解决方法如下:创建回调接口ResultSetHandler,利用回调函数的方式动态创建操作结果集的实体类对象,然后把实体类对象返回即可。

首先是DBUtils:

public class DBUtils {
private static String URL;
private static String username;
private static String password;
private static String driver;

static{
//获取配置文件信息
ResourceBundle res = ResourceBundle.getBundle("com.java.dbutils.jdbc-config");
URL = res.getString("jdbc-URL");
username = res.getString("jdbc-userName");
password = res.getString("jdbc-password");
driver = res.getString("jdbc-Driver");
try {
//加载驱动
Class.forName(driver);
System.out.println("加载驱动成功");
} catch (ClassNotFoundException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
System.out.println("加载驱动失败");
}
}

public static Connection getConnection(){
//获取连接
Connection conn = null;
try {
conn = DriverManager.getConnection(URL,username,password);
System.out.println("获取连接成功");
} catch (SQLException e) {
// TODO 自动生成的 catch 块
System.out.println("获取连接失败");
e.printStackTrace();
}
return conn;
}

public static PreparedStatement getPreparedStatement(String sql){
PreparedStatement ppst = null;
try {
ppst = getConnection().prepareStatement(sql);
System.out.println("预编译成功");
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
System.out.println("预编译失败");
}
return ppst;
}
public static void closeALL(Connection conn,PreparedStatement ppst,ResultSet res){
try {
if(conn != null) conn.close();
if(ppst != null) ppst.close();
if(res != null) res.close();
System.out.println("关闭成功");
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
System.out.println("关闭失败");
}
}
public static void main(String[] args) {

}
}


JDBCTemplate:

public class jdbcTamplete {
@SuppressWarnings("finally")
public int update(String sql,Object...args){
Connection conn = null;
PreparedStatement ppst = null;
conn = DBUtils.getConnection();
int count = 0;
try {
ppst = conn.prepareStatement(sql);
for(int i=0;i<args.length;i++){
ppst.setObject(i+1, args[i]);
}
count = ppst.executeUpdate();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
System.out.println("更新失败");
}finally{
DBUtils.closeALL(conn, ppst, null);
System.out.println("关闭成功");
return count;
}
}

@SuppressWarnings("finally")
public Object query(String sql,ResultSetHandler rshd,Object... args){
Object object = null;
Connection conn = null;
PreparedStatement ppst = null;
ResultSet res = null;
try {
conn = DBUtils.getConnection();
//ppst = conn.prepareStatement("select * where ths_id = 2014051044");
ppst = conn.prepareStatement(sql);
if(args != null){
for(int i=0;i<args.length;i++){
ppst.setObject(i+1, args[i]);
}
}
res = ppst.executeQuery();
object = rshd.doHandler(res);
if(object == null){
System.out.println("null");

}
System.out.println("查询成功");
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
System.out.println("查询失败");
}finally {
DBUtils.closeALL(conn, ppst, res);
return object;
}
}
}


ResultSetHandler:

public interface ResultSetHandler {
public Object doHandler(ResultSet res) throws SQLException;
}

使用案例,查询所有部门信息:

@Override
public List<Department> queryDepartmentAll() {
// TODO 自动生成的方法存根
List<Department> deps = null;
String sql = "select * from department_test";
deps = (List<Department>) jdbcTamplete.query(sql, new ResultSetHandler() {
List<Department> departments =  new ArrayList<>();
@Override
public Object doHandler(ResultSet res) throws SQLException {
// TODO 自动生成的方法存根
while(res.next()){
Department department = new Department();
department.setDpmt_Name(res.getString(1));
department.setThs_ID(res.getInt(2));
department.setThs_Name(res.getString(3));
department.setThs_Sex(res.getString(4));
department.setThs_Work(res.getInt(5));
department.setThs_shWork(res.getInt(6));
departments.add(department);
//System.out.println(res.getInt(2));
}
return departments;
}
}, null);
return deps;
}



当然,如果你觉得脑子不够用了,也可以利用jdk1.7的新特性,try with resources,可以把资源声明在try之后的括号中,在try执行结束之后,资源会自动释放。(PS:其实我经常这样用,写个简单的CURD还是美滋滋)

举个例子:

public User get(String name) {
        User bean = null;
          
        String sql = "select * from User where name = ?";
        try (Connection c = DBUtil.getConnection(); PreparedStatement ps = c.prepareStatement(sql)) {
            ps.setString(1, name);
            ResultSet rs =ps.executeQuery();
  
            if (rs.next()) {
                bean = new User();
                int id = rs.getInt("id");
                bean.setName(name);
                String password = rs.getString("password");
                bean.setPassword(password);
                bean.setId(id);
            }
  
        } catch (SQLException e) {
  
            e.printStackTrace();
        }
        return bean;
    }


原创粉丝点击