posted @ 2017-02-26 18:04 阅读 (...) 评论 (...)
- 先来看一段常见的数据库操作代码:
- ```
- protected User getDataFromDatabase(long id){
- String sql = "select firstname from user where id=?";//1
- Connection conn = DBConnectionFactory.getConnection();
- PreparedStatement stat;
- User user;//2
- try {
- stat = conn.prepareStatement(sql);
- stat.setObject(1, id);
- ResultSet rs = stat.executeQuery();
- user.setFirstName(rs.getString("firstname"));//3
- stat.close();
- } catch (SQLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } finally {
- try {
- conn.close();
- } catch (SQLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- return user;
- }
- ```
- 在上面代码中存在三个可变部分,如果需要把数据库操作代码修改为任何对象都能使用的同一段代码,则需要提取出这三个可变部分。所以我们修改一下上面代码。
- 1、首先提取一下sql语句部分。如果我们可以动态生成该sql语句,数据库对象映射器应该就完成了一半。所以我们先来拆解sql语句,看看下面这段代码:
- ```
- String selectList="firstname";
- String whereClause="id=?";
- String tableName = "user";
- String sql = "select " + selectList +" from " + tableName +" where " + whereClause;
- protected User getDataFromDatabase(String sql,long id){
- //String sql = "select firstname from user where id=?";//1
- Connection conn = DBConnectionFactory.getConnection();
- PreparedStatement stat;
- User user;//2
- try {
- stat = conn.prepareStatement(sql);
- stat.setObject(1, id);
- ResultSet rs = stat.executeQuery();
- user.setFirstName(rs.getString("firstname"));//3
- stat.close();
- } catch (SQLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } finally {
- try {
- conn.close();
- } catch (SQLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- return user;
- }
- ```
- 拆解了第一部分,现在看起来好像也感觉差别不大,仅仅是把sql当作参数传递进去。关于第二第三可变部分,我们再来看看下面这段代码:
- ```
- String selectList="firstname";
- String whereClause="id=?";
- String tableName = "user";
- String sql = "select " + selectList +" from " + tableName +" where " + whereClause;
- Class klass = User.class;
- String fieldName = "firstName";
- String columnName = "firstname";
- Field field = klass.getDeclaredField(fieldName);
- protected Object getDataFromDatabase(String sql,Object id){
- //String sql = "select id,firstname from user where id=?";//1
- Connection conn = DBConnectionFactory.getConnection();
- PreparedStatement stat;
- Object user;//2
- try {
- stat = conn.prepareStatement(sql);
- stat.setObject(1, id);
- ResultSet rs = stat.executeQuery();
- user = klass.newInstance();
- field.set(user,rs.getObject(columnName));
- //user.setFirstName(rs.getString("firstname"));//3
- stat.close();
- } catch (SQLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } finally {
- try {
- conn.close();
- } catch (SQLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- return user;
- }
- ```
- 现在再重新看函数体内,与特定user对象的信息,好像没有了,当然这里为了简化问题,user对象只有一个firstname,后面会看到有多个变量时,仅仅是field.set()那里变成了一个for循环。然后我们再来优化一下代码,毕竟所有代码堆在一个地方乱七八糟,非常不容易理解。而且如果代码仅仅是这样的话,也没有任何的可重用性。我们先把函数体提取到BaseMapper.class。把其他可变的部分,提取到TableMap.class和OneToOneColumnMap.class。TableMap存储对象与数据库表映射信息,OneToOneColumnMap存储对象field与表列的映射信息。每一个对象都会有一个BaseMapper实例,存储各自的对象关系映射信息。代码如下:
- ```
- class BassMapper{
- protected TableMap tableMap;
- public Object getDataFromDatabase(String sql,Object... param){
- Connection conn = DBConnectionFactory.getConnection();
- PreparedStatement stat;
- Object result = null;
- try {
- stat = conn.prepareStatement(sql);
- for(int i = 0;i < param.length;i++){
- stat.setObject(i + 1, param[i]);
- }
- ResultSet rs = stat.executeQuery();
- if(rs.next()){
- result = (T) tableMap.getKlass().newInstance();
- for(Iterator it = tableMap.getOneToOneColumns();it.hasNext();){
- OneToOneColumnMap columnMap = it.next();
- Object columnValue = rs.getObject(columnMap.getColumnName());
- columnMap.setField(result, columnValue);
- }
- }
- stat.close();
- } catch (SQLException | InstantiationException | IllegalAccessException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } finally {
- try {
- conn.close();
- } catch (SQLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- return result;
- }
- }
- ```
- ```
- class OneToOneColumnMap{
- private String columnName;
- private String fieldName;
- protected Field field;
- private TableMap dataMap;
- public OneToOneColumnMap(String columnName,String fieldName,TableMap dataMap){
- this.columnName = columnName;
- this.fieldName = fieldName;
- this.dataMap = dataMap;
- initField();
- }
- public String getColumnName(){
- return this.columnName;
- }
- public String getFieldName(){
- return this.fieldName;
- }
- public Object getValue(Object subject){
- try {
- return field.get(subject);
- } catch (IllegalArgumentException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return null;
- }
- public void setField(Object result,Object columnValue){
- try {
- field.set(result, columnValue);
- } catch (IllegalArgumentException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- protected void initField(){
- try {
- this.field = dataMap.getKlass().getDeclaredField(getFieldName());
- field.setAccessible(true);
- } catch (NoSuchFieldException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (SecurityException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- ```
- ```
- class TableMap{
- private Class<T> domainClass;
- private String tableName;
- private OneToOneColumnMap primaryKeyColumn;
- private List<OneToOneColumnMap> oneToOneColumnMaps = new ArrayList<OneToOneColumnMap>();
- public TableMap(String tableName,Class<T> domainClass){
- this.domainClass = domainClass;
- this.tableName = tableName;
- }
- public void addOneToOneColumn(String columnName,String fieldName){
- OneToOneColumnMap columnMap = new OneToOneColumnMap(columnName,fieldName,this);
- if(!oneToOneColumnMaps.contains(columnMap)){
- if(primaryKeyColumn == null){
- primaryKeyColumn = columnMap;
- }
- oneToOneColumnMaps.add(columnMap);
- }
- }
- public void setPrimaryKeyColumn(String columnName, String fieldName){
- this.primaryKeyColumn = new OneToOneColumnMap(columnName,fieldName,this);
- if(!oneToOneColumnMaps.contains(primaryKeyColumn)){
- oneToOneColumnMaps.add(primaryKeyColumn);
- }
- }
- public String primaryKeyWhereClause(){
- return primaryKeyColumn.getColumnName() + " = ? ";
- }
- public Object primaryKeyColumnName(){
- return primaryKeyColumn.getColumnName();
- }
- public Object primaryKeyValue(Object domainObject){
- return primaryKeyColumn.getValue(domainObject);
- }
- public String getTableName(){
- return this.tableName;
- }
- public String insertList(){
- StringBuffer result = new StringBuffer("?");
- for(int i = 0;i < oneToOneColumnMaps.size() - 1;i++){
- result.append(",");
- result.append("?");
- }
- return result.toString();
- }
- public String columnList(){
- StringBuffer result = new StringBuffer(" ");
- for(Iterator<OneToOneColumnMap> it = getOneToOneColumns();it.hasNext();){
- OneToOneColumnMap columnMap = it.next();
- result.append(columnMap.getColumnName());
- result.append(",");
- }
- result.setLength(result.length() - 1);
- return result.toString();
- }
- public String updateList(){
- StringBuffer result = new StringBuffer(" SET ");
- for(Iterator<OneToOneColumnMap> it = getOneToOneColumns();it.hasNext();){
- OneToOneColumnMap column = it.next();
- result.append(column.getColumnName());
- result.append("=?,");
- }
- result.setLength(result.length() - 1);
- return result.toString();
- }
- public String getColumnForField(String fieldName){
- for(Iterator<OneToOneColumnMap> it = getOneToOneColumns();it.hasNext();){
- OneToOneColumnMap columnMap = it.next();
- if(columnMap.getFieldName().equals(fieldName)){
- return columnMap.getColumnName();
- }
- }
- return null;
- }
- }
- ```
- BaseMapper通过一个TableMap来初始化,依赖关系如下:
- ![这里写图片描述](http://img.blog.csdn.net/20170211104536444?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHV4dWVtaW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
- 项目代码:https://github.com/hu-xuemin/xBlog.git
来源: http://www.cnblogs.com/huxuemin/p/6445294.html