Java中JDBC的常見封裝
ThreadLocal
ThreadLocal API
ThreadLocal類只有三個方法:
l void set(T value):儲存值;
l T get():獲取值;
l void remove():移除值。
key |
value |
thread1 |
aaa |
thread2 |
bbb |
thread3 |
ccc |
ThreadLocal的內部是Map
ThreadLocal內部其實是個Map來儲存資料。雖然在使用ThreadLocal時只給出了值,沒有給出鍵,其實它內部使用了當前執行緒做為鍵。
class MyThreadLocal<T> { private public void set(T value) { map.put(Thread.currentThread(), value); } public void remove() { map.remove(Thread.currentThread()); } public T get() { return map.get(Thread.currentThread()); } } |
BaseServlet
BaseServlet的作用
在開始客戶管理系統之前,我們先寫一個工具類:BaseServlet。
我們知道,寫一個專案可能會出現N多個Servlet,而且一般一個Servlet只有一個方法(doGet或doPost),如果專案大一些,那麼Servlet的數量就會很多。
寫一個BaseServlet。它的作用是讓一個Servlet可以處理多種不同的請求。不同的請求呼叫Servlet的不同方法。我們寫好了BaseServlet後,讓其他Servlet繼承BaseServlet,例如CustomerServlet繼承BaseServlet,然後在CustomerServlet中提供add()、update()、delete()等方法,每個方法對應不同的請求。
BaseServlet分析
我們知道,Servlet中處理請求的方法是service()方法,這說明我們需要讓service()方法去呼叫其他方法。例如呼叫add()、mod()、del()、all()等方法!具體呼叫哪個方法需要在請求中給出方法名稱!然後service()方法通過方法名稱來呼叫指定的方法。
無論是點選超連結,還是提交表單,請求中必須要有method引數,這個引數的值就是要請求的方法名稱,這樣BaseServlet的service()才能通過方法名稱來呼叫目標方法。例如某個連結如下:
<a href=”/xxx/CustomerServlet?method=add”>新增客戶</a>
BaseServlet程式碼
public class BaseServlet extends HttpServlet { /* * 它會根據請求中的m,來決定呼叫本類的哪個方法 */ protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); res.setContentType("text/html;charset=utf-8"); // 例如:http://localhost:8080/demo1/xxx?method=add String methodName = req.getParameter("method");// 它是一個方法名稱 // 當沒用指定要呼叫的方法時,那麼預設請求的是execute()方法。 if(methodName == null || methodName.isEmpty()) { methodName = "execute"; } Class c = this.getClass(); try { // 通過方法名稱獲取方法的反射物件 Method m = c.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); // 反射方法目標方法,也就是說,如果methodName為add,那麼就呼叫add方法。 String result = (String) m.invoke(this, req, res); // 通過返回值完成請求轉發 if(result != null && !result.isEmpty()) { req.getRequestDispatcher(result).forward(req, res); } } catch (Exception e) { throw new ServletException(e); } } } |
DBUtils
DBUtils簡介
DBUtils是Apache Commons元件中的一員,開源免費!
DBUtils是對JDBC的簡單封裝,但是它還是被很多公司使用!
DBUtils的Jar包:dbutils.jar
DBUtils主要類
l DbUtils:都是靜態方法,一系列的close()方法;
l QueryRunner:
Ø update():執行insert、update、delete;
Ø query():執行select語句;
Ø batch():執行批處理。
QueryRunner之更新
QueryRunner的update()方法可以用來執行insert、update、delete語句。
1. 建立QueryRunner
構造器:QueryRunner();
2. update()方法
intupdate(Connection con, String sql, Object… params)
@Test public void fun1() throws SQLException { QueryRunner qr = new QueryRunner(); String sql = "insert into user values(?,?,?)"; qr.update(JdbcUtils.getConnection(), sql, "u1", "zhangSan", "123"); } |
還有另一種方式來使用QueryRunner
1. 建立QueryRunner
構造器:QueryRunner(DataSource)
2. update()方法
intupdate(String sql, Object… params)
這種方式在建立QueryRunner時傳遞了連線池物件,那麼在呼叫update()方法時就不用再傳遞Connection了。
@Test public void fun2() throws SQLException { QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource()); String sql = "insert into user values(?,?,?)"; qr.update(sql, "u1", "zhangSan", "123"); } |
ResultSetHandler
執行select語句之後得到的是ResultSet,然後我們還需要對ResultSet進行轉換,得到最終我們想要的資料。你可以希望把ResultSet的資料放到一個List中,也可能想把資料放到一個Map中,或是一個Bean中。
DBUtils提供了一個介面ResultSetHandler,它就是用來ResultSet轉換成目標型別的工具。你可以自己去實現這個介面,把ResultSet轉換成你想要的型別。
DBUtils提供了很多個ResultSetHandler介面的實現,這些實現已經基本夠用了,我們通常不用自己去實現ResultSet介面。
l MapHandler:單行處理器!把結果集轉換成Map<String,Object>,其中列名為鍵!
l MapListHandler:多行處理器!把結果集轉換成List<Map<String,Object>>;
l BeanHandler:單行處理器!把結果集轉換成Bean,該處理器需要Class引數,即Bean的型別;
l BeanListHandler:多行處理器!把結果集轉換成List<Bean>;
l ColumnListHandler:多行單列處理器!把結果集轉換成List<Object>,使用ColumnListHandler時需要指定某一列的名稱或編號,例如:new ColumListHandler(“name”)表示把name列的資料放到List中。
l ScalarHandler:單行單列處理器!把結果集轉換成Object。一般用於聚集查詢,例如select count(*) from tab_student。
QueryRunner之查詢
QueryRunner的查詢方法是:
public<T> T query(String sql, ResultSetHandler<T> rh, Object… params)
public<T> T query(Connection con, String sql, ResultSetHandler<T> rh,Object… params)
query()方法會通過sql語句和params查詢出ResultSet,然後通過rh把ResultSet轉換成對應的型別再返回。
@Test public void fun1() throws SQLException { DataSource ds = JdbcUtils.getDataSource(); QueryRunner qr = new QueryRunner(ds); String sql = "select * from tab_student where number=?"; Map<String,Object> map = qr.query(sql, new MapHandler(), "d_2000"); System.out.println(map); } @Test public void fun2() throws SQLException { DataSource ds = JdbcUtils.getDataSource(); QueryRunner qr = new QueryRunner(ds); String sql = "select * from tab_student"; List<Map<String,Object>> list = qr.query(sql, new MapListHandler()); for(Map<String,Object> map : list) { System.out.println(map); } } @Test public void fun3() throws SQLException { DataSource ds = JdbcUtils.getDataSource(); QueryRunner qr = new QueryRunner(ds); String sql = "select * from tab_student where number=?"; Student stu = qr.query(sql, new BeanHandler<Student>(Student.class), "d_2000"); System.out.println(stu); } @Test public void fun4() throws SQLException { DataSource ds = JdbcUtils.getDataSource(); QueryRunner qr = new QueryRunner(ds); String sql = "select * from tab_student"; List<Student> list = qr.query(sql, new BeanListHandler<Student>(Student.class)); for(Student stu : list) { System.out.println(stu); } } @Test public void fun5() throws SQLException { DataSource ds = JdbcUtils.getDataSource(); QueryRunner qr = new QueryRunner(ds); String sql = "select * from tab_student"; List<Object> list = qr.query(sql, new ColumnListHandler("name")); for(Object s : list) { System.out.println(s); } } @Test public void fun6() throws SQLException { DataSource ds = JdbcUtils.getDataSource(); QueryRunner qr = new QueryRunner(ds); String sql = "select count(*) from tab_student"; Number number = (Number)qr.query(sql, new ScalarHandler()); int cnt = number.intValue(); System.out.println(cnt); } |
QueryRunner之批處理
QueryRunner還提供了批處理方法:batch()。
我們更新一行記錄時需要指定一個Object[]為引數,如果是批處理,那麼就要指定Object[][]為引數了。即多個Object[]就是Object[][]了,其中每個Object[]對應一行記錄:
@Test public void fun() throws SQLException { DataSource ds = JdbcUtils.getDataSource(); QueryRunner qr = new QueryRunner(ds); String sql = "insert into tab_student values(?,?,?,?)"; Object[][] params = new Object[10][];//表示要插入10行記錄 for(int i = 0; i < params.length; i++) { params[i] = new Object[]{"d_300" + i, "name" + i, 30 + i, i%2==0?"男":"女"}; } qr.batch(sql, params); } |