对mybatis理解的还不是特别深刻,只会简单的使用,实现这个功能跟平常使用spring+mybatis时的DAO操作有点类似,spring+mybatis具体内部实现还不清楚,后续要继续学习
代码:
1. 实体类:
1 package com.mrlu.concurrency.domain;
2
3 /**
4 * Created by stefan on 15-12-19.
5 */
6 public class Goods {
7 private Integer id;
8 private Integer count;
9
10 public Integer getId() {
11 return id;
12 }
13
14 public void setId(Integer id) {
15 this.id = id;
16 }
17
18 public Integer getCount() {
19 return count;
20 }
21
22 public void setCount(Integer count) {
23 this.count = count;
24 }
25
26 @Override
27 public String toString() {
28 return "Goods{" +
29 "id=" + id +
30 ", count=" + count +
31 '}';
32 }
33 }
2. DAO:
1 package com.mrlu.concurrency.dao;
2
3 import com.mrlu.concurrency.domain.Goods;
4 import com.mrlu.concurrency.sqloperation.SQLSessionFactory;
5 import java.util.List;
6
7 /**
8 * Created by stefan on 15-12-19.
9 */
10 public class GoodsDao {
11 private SQLSessionFactory sqlSessionFactory;
12
13 public void insert(Goods goods){
14 System.out.println("insert into table goods....");
15 String sql = "insert into goods(count) values(?)";
16 sqlSessionFactory.insert(sql, new Object[]{goods.getCount()});
17 }
18
19 public void update(Goods goods){
20 System.out.println("update table goods....");
21 String sql = "UPDATE goods SET count =? WHERE id = ?";
22 sqlSessionFactory.update(sql, new Object[]{goods.getCount(), goods.getId()});
23 }
24
25 public List<Goods> select(){
26 System.out.println("select table goods....");
27 String sql = "SELECT * FROM goods";
28 List<Goods> resultList = sqlSessionFactory.select(sql, new Object[]{}, Goods.class);
29 System.out.println("select count: " + resultList.size());
30 return resultList;
31 }
32
33 public SQLSessionFactory getSqlSessionFactory() {
34 return sqlSessionFactory;
35 }
36
37 public void setSqlSessionFactory(SQLSessionFactory sqlSessionFactory) {
38 this.sqlSessionFactory = sqlSessionFactory;
39 }
40 }
3. 提供代理操作方法的类,并提供创建代理类对象:
1 package com.mrlu.concurrency.daoProxy;
2
3 import org.springframework.cglib.proxy.Enhancer;
4 import org.springframework.cglib.proxy.MethodInterceptor;
5 import org.springframework.cglib.proxy.MethodProxy;
6
7 import java.lang.reflect.Field;
8 import java.lang.reflect.Method;
9 import java.sql.*;
10 import java.util.LinkedList;
11 import java.util.List;
12
13 /**
14 * Created by stefan on 15-12-21.
15 */
16 public class SQLSessionProxy implements MethodInterceptor{
17 private Enhancer enhancer = new Enhancer();
18 private static List<Connection> connectionPool = new LinkedList<>();
19
20 public Object getProxy(Class clazz){
21 enhancer.setSuperclass(clazz);
22 enhancer.setCallback(this);
23 return enhancer.create();
24 }
25
26 static{
27 try {
28 Class.forName("com.mysql.jdbc.Driver");
29 String url = "jdbc:mysql://127.0.0.1:3306/concurrency";
30 String userName = "root";
31 String password = "123456a";
32 for(int i=0; i<10; i++){
33 Connection connection = DriverManager.getConnection(url, userName, password);
34 connectionPool.add(connection);
35 }
36 }catch (Exception e){
37 e.printStackTrace();
38 }
39
40 }
41
42 public void init(Object o){ //注意操作的都是代理对象,不能使用this,this不代表代理对象
43 System.out.println("init......."+ o);
44 if(connectionPool.isEmpty()){
45 return;
46 }
47 System.out.println("class: " + o);
48 System.out.println("class: " + o.getClass().getSuperclass());
49 Field[] fields = o.getClass().getSuperclass().getDeclaredFields(); //避免private,protected修饰的属性拿不到
50 Connection connection = connectionPool.get(0);
51 connectionPool.remove(0);
52 for(Field field: fields){
53 field.setAccessible(true); //此处设置任何属性都能拿到
54 if(field.getName().equals("connection")){
55 try {
56 field.set(o, connection);
57 } catch (IllegalAccessException e) {
58 e.printStackTrace();
59 }
60 break;
61 }
62 }
63 }
64
65 public void destory(Object o){
66 System.out.println("destory......." + o);
67 Field[] fields = o.getClass().getSuperclass().getDeclaredFields();
68 try {
69 for(Field field: fields){
70 field.setAccessible(true);
71 if(field.getName().equals("connection")){
72 Connection connection = (Connection) field.get(o);
73 if(connection != null){
74 connectionPool.add(connection);
75 }
76 }else if(field.getName().equals("preparedStatement")){
77 PreparedStatement preparedStatement = (PreparedStatement) field.get(o);
78 if(preparedStatement != null) {
79 preparedStatement.close();
80 }
81 }else if(field.getName().equals("resultSet")){
82 ResultSet resultSet = (ResultSet) field.get(o);
83 if(resultSet != null) {
84 resultSet.close();
85 }
86 }
87 }
88 } catch (Exception e) {
89 e.printStackTrace();
90 }
91 }
92
93 @Override
94 public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
95 if(method.getName().equals("insert") || method.getName().equals("update") || method.getName().equals("select")) { //注意此处的校验是特别有必要的,为了避免陷入无限递归循环中,因为不论调用代理对象的哪个方法都会交给代理方法来处理
96 Object result = null;
init(o);
97 if (method.getName().equals("select")) {
98 result = methodProxy.invokeSuper(o, objects); //select需返回查询结果
99 }
100 methodProxy.invokeSuper(o, objects);
101 destory(o); //此处很重要,需要回收链接
return result;
102 }
103 return null;
104 }
105 }
4. 封装的SQLSessionFactory
1 package com.mrlu.concurrency.sqloperation;
2
3 import java.lang.reflect.Field;
4 import java.sql.*;
5 import java.util.HashMap;
6 import java.util.LinkedList;
7 import java.util.List;
8 import java.util.Map;
9
10 /**
11 * Created by stefan on 15-12-21.
* 内部处理异常,无须抛到DAO去,DAO也不关心数据库操作异常
12 */
13 public class SQLSessionFactory{
14 private Connection connection = null;
15 private PreparedStatement preparedStatement = null;
16 private ResultSet resultSet = null;
17
18 public void insert(String sql, Object[] args){
19 System.out.println("[SQLSessionFactory] insert into table goods....");
20 try {
21 preparedStatement = connection.prepareStatement(sql);
22 for(int i=0; i < args.length;){
23 Object object = args[i];
24 preparedStatement.setObject(++i, object);
25 }
26 int updateCount = preparedStatement.executeUpdate();
27 System.out.println("[SQLSessionFactory] updateCount: " + updateCount);
28 }catch (SQLException e){
29 e.printStackTrace();
30 }
31 }
32
33 public void update(String sql, Object[] args){
34 try {
35 System.out.println("[SQLSessionFactory] update table goods....");
36 preparedStatement = connection.prepareStatement(sql);
37 for(int i=0; i < args.length;){
38 Object object = args[i];
39 preparedStatement.setObject(++i, object);
40 }
41 int updateCount = preparedStatement.executeUpdate();
42 System.out.println("[SQLSessionFactory] updateCount: " + updateCount);
43 }catch (SQLException e){
44 e.printStackTrace();
45 }
46 }
47
48 public <T> List<T> select(String sql, Object[] args, Class returnType){
49 List<T> list = null;
50 try {
51 System.out.println("[SQLSessionFactory] select table goods....");
52 preparedStatement = connection.prepareStatement(sql);
53 for (int i = 0; i < args.length; ) {
54 Object object = args[i];
55 preparedStatement.setObject(++i, object);
56 }
57 resultSet = preparedStatement.executeQuery();
58
59 List<Map<String, Object>> result = new LinkedList<>();
60 ResultSetMetaData metaData = resultSet.getMetaData();
61 int columnCount = metaData.getColumnCount();
62 while (resultSet.next()) {
63 Map<String, Object> maps = new HashMap<>();
64 for (int i = 0; i < columnCount; ) {
65 maps.put(metaData.getColumnName(++i), resultSet.getObject(i));
66 }
67 result.add(maps);
68 }
69 System.out.println("[SQLSessionFactory] select: " + result.size());
70 list = transferResultToObject(result, returnType);
71 }catch (SQLException e){
72 e.printStackTrace();
73 }
74 return list;
75 }
76
77 private <T> List<T> transferResultToObject(List<Map<String, Object>> result, Class returnType) { //此处用到了泛型(方法返回值泛型)和反射, 泛型需要注意类型擦除
78 Field[] fields = returnType.getDeclaredFields();
79 List resultObject = new LinkedList<>();
80 try {
81 for (Map<String, Object> map: result) {
82 Object eachResult = returnType.newInstance();
83 for (Field field : fields) {
84 field.setAccessible(true);
85 Object object = map.get(field.getName());
86 field.set(eachResult, object);
87 }
88 resultObject.add(eachResult);
89 }
90 }catch (Exception e){
91 e.printStackTrace();
92 }
93 return resultObject;
94 }
95
96 public Connection getConnection() {
97 return connection;
98 }
99
100 public void setConnection(Connection connection) {
101 this.connection = connection;
102 }
103
104 public PreparedStatement getPreparedStatement() {
105 return preparedStatement;
106 }
107
108 public void setPreparedStatement(PreparedStatement preparedStatement) {
109 this.preparedStatement = preparedStatement;
110 }
111
112 public ResultSet getResultSet() {
113 return resultSet;
114 }
115
116 public void setResultSet(ResultSet resultSet) {
117 this.resultSet = resultSet;
118 }
119 }
5. 测试:
1 package com.mrlu.concurrency;
2
3 import com.mrlu.concurrency.dao.GoodsDao;
4 import com.mrlu.concurrency.daoProxy.DaoProxy;
5 import com.mrlu.concurrency.daoProxy.SQLSessionProxy;
6 import com.mrlu.concurrency.domain.Goods;
7 import com.mrlu.concurrency.sqloperation.SQLSessionFactory;
8
9 import java.util.List;
10
11 /**
12 * Created by stefan on 15-12-17.
13 */
14 public class Main {
15 public static void main(String[] args){
16 SQLSessionProxy proxy = new SQLSessionProxy();
17 SQLSessionFactory sqlSessionFactory = (SQLSessionFactory) proxy.getProxy(SQLSessionFactory.class); //创建SQLSessionFactory,注意若在多线程中使用sqlSessionFactory,则需为每个线程创建一个sqlSessionFactory对象,因为sqlSessionFactory是有状态的(和PrepareStatement,Connection,ResultSet有关联),无法保证线程之间互不影响(一个线程关闭了PrepareStatement,另一个在用的时候就会出错,或其中一个线程通过反射修改了connection对象的引用,导致原来的connection对象永远不能关闭,内存泄露),这就说明了为什么单例对象都是无状态的
18
19 GoodsDao goodsDao = new GoodsDao();
20 goodsDao.setSqlSessionFactory(sqlSessionFactory); //注入依赖
21
22 Goods goods = new Goods();
23 goods.setCount(30);
24 goodsDao.insert(goods); //执行数据库操作
25
26 List<Goods> list = goodsDao.select(); //拿到返回值结果,完全利用泛型的在必要的时候类型转换的特性
27 for (Goods goods1: list){
28 System.out.println(goods1);
29 }
30 System.out.println(list);
31 }
32 }