范文健康探索娱乐情感热点
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

深入Mybatis

  1 前言
  大家都知道MyBatis是我们常用的一个持久层框架,那么今天我们就来深入MyBatis底层,来探究MyBatis到底是怎么实现数据库操作的呢? 2 持久层的开发模式
  1 传统的开发模式
  接口定义业务方法 public interface UserService {     public User getUserById(int id); }
  实现类实现接口方法 (sql语句写在java代码里面) public class UserServiceImpl implements UserService{      @Override     public User getUserById(int id) {         Connection conn = JDBCTools.getConnection();         String sql = "select * from user where id = ?";         PreparedStatement pstmt = null;         ResultSet rs = null;         try {             pstmt = conn.prepareStatement(sql);             pstmt.setInt(1, id);             rs = pstmt.executeQuery();             if(rs.next()){                 int sid = rs.getInt(1);                 String name = rs.getString(2);                 User user = new User(sid,name);                 return user;             }         } catch (Exception e) {             // TODO Auto-generated catch block             e.printStackTrace();         }finally{             JDBCTools.release(conn, pstmt, rs);         }         return null;     } }
  测试 @Test   public void f1() throws Exception{        UserService userService = new UserServiceImpl();       User user = userService.getUserById(1);       System.out.println(user);    }
  2 Mybatis的开发模式
  定义接口方法 public interface UserMapper {      public User getUserById(int id);  }
  接口对应的映射xml文件(sql语句写在xml文件) <?xml version="1.0" encoding="UTF-8" ?>            
  测试 @Test public void f1() throws Exception{      UserMapper mapper = (UserMapper) new MyInvocationHandler().getInstance(UserMapper.class);     User user = mapper.getUserById(1);     System.out.println(user);  }
  通过以上代码可以看到,MyBatis的方式省去了实现类的创建,改为用xml来定义业务方法的具体实现
  为什么MyBatis可以不用通过实例化对象来操作我们的代码呢?这里就不得不说说jdk的动态代理
  jdk动态代理运行时结合接口和mapper.xml来动态创建一个代理对象,程序调用该代理对象的方法来完成业务 3 jdk动态代理
  创建一个类,实现InvocationHandler接口
  1 自定义getInstance方法:入参为目标对象,通过Proxy.newProxyInstance方法创建代理对象,并返回
  2 实现接口的invoke方法,通过反射机制完成业务逻辑代码
  invoke方法是核心代码,在该方法中实现具体的业务需求
  3 使用invoke方法解析数据库信息配置xml,创建数据库连接对象 //读取数据源配置信息     public static Map getProperties(){         Map map = new HashMap();         SAXReader reader = new SAXReader();         try {             Document document = reader.read("src/config.xml");             //获取根节点             Element root = document.getRootElement();             Iterator iter = root.elementIterator();             while(iter.hasNext()){                 Element e = (Element) iter.next();                 //解析environments节点                 if("environments".equals(e.getName())){                     Iterator iter2 = e.elementIterator();                     while(iter2.hasNext()){                         //解析environment节点                         Element e2 = (Element) iter2.next();                         Iterator iter3 = e2.elementIterator();                         while(iter3.hasNext()){                             Element e3 = (Element) iter3.next();                             //解析dataSource节点                             if("dataSource".equals(e3.getName())){                                 if("POOLED".equals(e3.attributeValue("type"))){                                     Iterator iter4 = e3.elementIterator();                                     //获取数据库连接信息                                     while(iter4.hasNext()){                                         Element e4 = (Element) iter4.next();                                         map.put(e4.attributeValue("name"),e4.attributeValue("value"));                                     }                                 }                             }                         }                     }                 }             }         } catch (Exception e) {             // TODO Auto-generated catch block             e.printStackTrace();         }         return map;      } //获取信息,创建数据源对象 Map map = ParseXML.getProperties(); ComboPooledDataSource datasource = new ComboPooledDataSource(); datasource.setDriverClass(map.get("driver")); datasource.setJdbcUrl(map.get("url")); datasource.setUser(map.get("username")); datasource.setPassword(map.get("password")); datasource.setInitialPoolSize(20); datasource.setMaxPoolSize(40); datasource.setMinPoolSize(2); datasource.setAcquireIncrement(5); Connection conn = datasource.getConnection();4 反射
  数据库连接,接下来就需要获取待执行的SQL语句,sql的定义全部写在UserMapper.xml中;解析xml执行sql语句,执行完毕,查询结果会保存在ResultSet中,还需要将ResultSet对象中的数据进行解析,封装到JavaBean中返回
  上述步骤通过两步实现
  第一步:反射机制创建User对象
  第二步:通过反射动态执行类中所有属性的setter方法,完成赋值 //获取sql语句 String sql = element.getText(); //获取参数类型 String parameterType = element.attributeValue("parameterType"); //创建pstmt PreparedStatement pstmt = createPstmt(sql,parameterType,conn,args); ResultSet rs = pstmt.executeQuery(); if(rs.next()){     //读取返回数据类型     String resultType = element.attributeValue("resultType");        //反射创建对象     Class clazz = Class.forName(resultType);     obj = clazz.newInstance();     //获取ResultSet数据     ResultSetMetaData rsmd = rs.getMetaData();     //遍历实体类属性集合,依次将结果集中的值赋给属性     Field[] fields = clazz.getDeclaredFields();     for(int i = 0; i < fields.length; i++){         Object value = setFieldValueByResultSet(fields[i],rsmd,rs);         //通过属性名找到对应的setter方法         String name = fields[i].getName();         name = name.substring(0, 1).toUpperCase() + name.substring(1);         String MethodName = "set"+name;         Method methodObj = clazz.getMethod(MethodName,fields[i].getType());         //调用setter方法完成赋值         methodObj.invoke(obj, value);         } }
  代码的实现大致思路如上所述,具体实现起来有很多细节需要处理 5 工具类
  上述操作使用的两个工具类完整代码如下
  ParseXML public class ParseXML {      //读取数据源配置信息     public static Map getProperties(){         Map map = new HashMap();         SAXReader reader = new SAXReader();         try {             Document document = reader.read("src/config.xml");             //获取根节点             Element root = document.getRootElement();             Iterator iter = root.elementIterator();             while(iter.hasNext()){                 Element e = (Element) iter.next();                 //解析environments节点                 if("environments".equals(e.getName())){                     Iterator iter2 = e.elementIterator();                     while(iter2.hasNext()){                         //解析environment节点                         Element e2 = (Element) iter2.next();                         Iterator iter3 = e2.elementIterator();                         while(iter3.hasNext()){                             Element e3 = (Element) iter3.next();                             //解析dataSource节点                             if("dataSource".equals(e3.getName())){                                 if("POOLED".equals(e3.attributeValue("type"))){                                     Iterator iter4 = e3.elementIterator();                                     //获取数据库连接信息                                     while(iter4.hasNext()){                                         Element e4 = (Element) iter4.next();                                         map.put(e4.attributeValue("name"),e4.attributeValue("value"));                                     }                                 }                             }                         }                     }                 }             }         } catch (Exception e) {             // TODO Auto-generated catch block             e.printStackTrace();         }         return map;      }      //根据接口查找对应的mapper.xml     public static String getMapperXML(String className){         //保存xml路径         String xml = "";         SAXReader reader = new SAXReader();         Document document;         try {             document = reader.read("src/config.xml");             Element root = document.getRootElement();             Iterator iter = root.elementIterator();             while(iter.hasNext()){                 Element mappersElement = (Element) iter.next();                 if("mappers".equals(mappersElement.getName())){                     Iterator iter2 = mappersElement.elementIterator();                     while(iter2.hasNext()){                         Element mapperElement = (Element) iter2.next();                         //com.cehnjie.dao.StudentDAO . 替换 #                         className = className.replace(".", "#");                         //获取接口结尾名                         String classNameEnd = className.split("#")[className.split("#").length-1];                         String resourceName = mapperElement.attributeValue("resource");                         //获取resource结尾名                         String resourceName2 = resourceName.split("/")[resourceName.split("/").length-1];                         //StudentDAO.xml . 替换 #                         resourceName2 = resourceName2.replace(".", "#");                         String resourceNameEnd = resourceName2.split("#")[0];                         if(classNameEnd.equals(resourceNameEnd)){                             xml="src/"+resourceName;                         }                     }                 }             }         } catch (DocumentException e) {             // TODO Auto-generated catch block             e.printStackTrace();         }         return xml;     } }
  MyInvocationHandler public class MyInvocationHandler implements InvocationHandler{      private String className;      public Object getInstance(Class cls){         //保存接口类型         className = cls.getName();         Object newProxyInstance = Proxy.newProxyInstance(                   cls.getClassLoader(),                   new Class[] { cls },                  this);          return (Object)newProxyInstance;     }      public Object invoke(Object proxy, Method method, Object[] args)  throws Throwable {                 SAXReader reader = new SAXReader();         //返回结果         Object obj = null;         try {             //获取对应的mapper.xml             String xml = ParseXML.getMapperXML(className);             Document document = reader.read(xml);             Element root = document.getRootElement();             Iterator iter = root.elementIterator();             while(iter.hasNext()){                 Element element = (Element) iter.next();                 String id = element.attributeValue("id");                 if(method.getName().equals(id)){                     //获取信息,创建数据源对象                     Map map = ParseXML.getProperties();                     ComboPooledDataSource datasource = new ComboPooledDataSource();                     datasource.setDriverClass(map.get("driver"));                     datasource.setJdbcUrl(map.get("url"));                     datasource.setUser(map.get("username"));                     datasource.setPassword(map.get("password"));                     datasource.setInitialPoolSize(20);                     datasource.setMaxPoolSize(40);                     datasource.setMinPoolSize(2);                     datasource.setAcquireIncrement(5);                     Connection conn = datasource.getConnection();                     //获取sql语句                     String sql = element.getText();                     //获取参数类型                     String parameterType = element.attributeValue("parameterType");                     //创建pstmt                     PreparedStatement pstmt = createPstmt(sql,parameterType,conn,args);                     ResultSet rs = pstmt.executeQuery();                     if(rs.next()){                         //读取返回数据类型                         String resultType = element.attributeValue("resultType");                            //反射创建对象                         Class clazz = Class.forName(resultType);                         obj = clazz.newInstance();                         //获取ResultSet数据                         ResultSetMetaData rsmd = rs.getMetaData();                         //遍历实体类属性集合,依次将结果集中的值赋给属性                         Field[] fields = clazz.getDeclaredFields();                         for(int i = 0; i < fields.length; i++){                             Object value = setFieldValueByResultSet(fields[i],rsmd,rs);                             //通过属性名找到对应的setter方法                             String name = fields[i].getName();                             name = name.substring(0, 1).toUpperCase() + name.substring(1);                             String MethodName = "set"+name;                             Method methodObj = clazz.getMethod(MethodName,fields[i].getType());                             //调用setter方法完成赋值                             methodObj.invoke(obj, value);                         }                     }                     conn.close();                 }             }         } catch (Exception e) {             // TODO Auto-generated catch block             e.printStackTrace();         }         return obj;     }      /**      * 根据条件创建pstmt      * @param sql      * @param parameterType      * @param conn      * @param args      * @return      * @throws Exception      */     public PreparedStatement createPstmt(String sql,String parameterType,Connection conn,Object[] args) throws Exception{         PreparedStatement pstmt = null;         try {             switch(parameterType){                 case "int":                     int start = sql.indexOf("#{");                     int end = sql.indexOf("}");                     //获取参数占位符 #{name}                     String target = sql.substring(start, end+1);                     //将参数占位符替换为?                     sql = sql.replace(target, "?");                     pstmt = conn.prepareStatement(sql);                     int num = Integer.parseInt(args[0].toString());                     pstmt.setInt(1, num);                     break;                 case "java.lang.String":                     int start2 = sql.indexOf("#{");                     int end2 = sql.indexOf("}");                     String target2 = sql.substring(start2, end2+1);                     sql = sql.replace(target2, "?");                     pstmt = conn.prepareStatement(sql);                     String str = args[0].toString();                     pstmt.setString(1, str);                     break;                 default:                     Class clazz = Class.forName(parameterType);                     Object obj = args[0];                     boolean flag = true;                     //存储参数                     List values = new ArrayList();                     //保存带#的sql                     String sql2 = "";                     while(flag){                         int start3 = sql.indexOf("#{");                         //判断#{}是否替换完成                         if(start3<0){                             flag = false;                             break;                         }                         int end3 = sql.indexOf("}");                         String target3 = sql.substring(start3, end3+1);                         //获取#{}的值 如#{name}拿到name                         String name = sql.substring(start3+2, end3);                         //通过反射获取对应的getter方法                         name = name.substring(0, 1).toUpperCase() + name.substring(1);                         String MethodName = "get"+name;                         Method methodObj = clazz.getMethod(MethodName);                         //调用getter方法完成赋值                         Object value = methodObj.invoke(obj);                         values.add(value);                         sql = sql.replace(target3, "?");                         sql2 = sql.replace("?", "#");                     }                     //截取sql2,替换参数                     String[] sqls = sql2.split("#");                     pstmt = conn.prepareStatement(sql);                     for(int i = 0; i < sqls.length-1; i++){                         Object value = values.get(i);                         if("java.lang.String".equals(value.getClass().getName())){                             pstmt.setString(i+1, (String)value);                         }                         if("java.lang.Integer".equals(value.getClass().getName())){                             pstmt.setInt(i+1, (Integer)value);                         }                     }                     break;                 }         } catch (SQLException e) {             // TODO Auto-generated catch block             e.printStackTrace();         }         return pstmt;     }      /**      * 根据将结果集中的值赋给对应的属性      * @param field      * @param rsmd      * @param rs      * @return      */     public Object setFieldValueByResultSet(Field field,ResultSetMetaData rsmd,ResultSet rs){         Object result = null;         try {             int count = rsmd.getColumnCount();             for(int i=1;i<=count;i++){                 if(field.getName().equals(rsmd.getColumnName(i))){                     String type = field.getType().getName();                     switch (type) {                         case "int":                             result = rs.getInt(field.getName());                             break;                         case "java.lang.String":                             result = rs.getString(field.getName());                             break;                     default:                         break;                     }                 }             }         } catch (SQLException e) {             // TODO Auto-generated catch block             e.printStackTrace();         }         return result;     }   }6 总结
  ​ MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理 。多学习研究优秀框架的实现思路,对提升自己的编码能力大有裨益 。
整形医生大实话这些医美项目千万别做,失败率高还难以修复!当今社会,是一个信息爆炸的社会。关于医美整形,不仅有专业医生做科普,还有很多网络达人(以过来人的身份)也会做科普,网络上充斥着各种各样的信息,让人真假难辨!一些信息产品,往往背后早姆巴佩与梅西内马尔矛盾进一步激化,世界杯后已6场没有互相助攻在卡塔尔世界杯中,巴黎圣日耳曼可谓表现最成功最出色的俱乐部,半决赛四支球队中阿根廷法国和摩洛哥三队都有巴黎球员。梅西和姆巴佩不仅分别率领阿根廷和法国杀入了决赛,梅西带领阿根廷夺冠之CBA广东队第二阶段评分祝贺广东队以战胜辽宁,结束了CBA第二阶段的比赛,以第二阶段17胜2负,全部比赛22胜6负排在积分榜第三位。相比第一阶段,第二阶段广东队的表现逐渐进入正轨,在取得比赛胜利的前提下,巴克利现役仅有5人,能在我那个时代夺冠,库里很难适应那时代巴克利认为现在NBA中,只有5个人能有能力带队夺冠,分别是詹姆斯,字母哥,杜兰特,伦纳德,欧文。还有巴克利认为库里不适应他那个年代,他那个年代能把库里防的找不到西北,库里甚至三分球女棋手唐奕棋之道所凭非孤勇今天向大家介绍的这位藏品捐赠人,是从上海走向全国乃至世界舞台的围棋四段女棋手唐奕。从11岁至22岁,她曾三度以选手身份参加市运会。她所获得的第一名奖状,目前正展示在市运会主题展进门经纪人新年前夕阿尔特塔打电话给基维奥尔,把他给迷住了波兰国脚,斯佩齐亚中卫基维奥尔的经纪人RafaKdzior参与了波兰媒体Meczyki的直播。就在新年夜(1月1号)前夕,基维奥尔和阿尔特塔进行了电话交谈,他告诉了他很多细节,为他(体育)足球英超阿森纳胜曼联当日,在20222023英格兰足球超级联赛第21轮比赛中,阿森纳队主场以3比2战胜曼彻斯特联队。1月22日,阿森纳队球员恩凯蒂亚(右二)在比赛中破门。新华社路透1月22日,曼联队球勇网之战,欧文再次爆发,砍下38分带队逆风翻盘勇士今天NBA常规赛迎来了一场焦点大战,篮网客场挑战勇士队,虽然篮网队杜兰特因伤无法出战,但是篮网队这边欧文近期状态火热,比赛开场就呈现焦灼状态,虽然勇士队一度领先了篮网队17分之多,蒙蒂布克目前只能做无接触训练还没有确切的重新评估日期直播吧1月23日讯今日NBA常规赛,太阳将在主场迎战灰熊。赛前,蒙蒂接受了媒体采访。谈到布克的恢复进展,他说后者目前只能够做一些无接触的训练。他并未给出给布克重新评估的确切日期,但篮网逆转勇士!欧文安慰小库里,库里自责与兄弟畅聊,赵四淡定今天勇士和篮网的比赛确实神奇,毕竟篮网在末节完成逆转。别忘了,大比分时间勇士都保持优势的,可惜的是,今天库里末节连续打铁,汤普森和维金斯也无法站出来帮助球队,这都是这场比赛的瑕疵,中大纺织商圈停摆,美邦库存高危,22年服装圈大事件回顾!回望过去365天对于鞋服行业来说用动荡一词不足为过,疫情的硝烟击退了不少行业,在很多关键热点事件中小编也发表了对应文章观点,如今翻看总结,仍历历在目。一星期六拖鞋当主业不赚钱时,那
为啥你家儿子总是听不到你说话?做好4点,孩子乖乖听讲还很开心说了一万遍,孩子就是听不到,怎么办呀?如果你也有这样的烦恼,看完这篇文章,肯定有很大的收获。干货有点多,记不住没关系,收藏这篇文章反复观看就能内化于心了。妈妈炒完菜从厨房出来,提醒刺客伍六七师姐的人设是最大败笔?不过是导演在转移话题罢了!刺客伍六七动画如今已经更新到第七集啦,看到现在,发现很多小伙伴都觉得江慧莲的人设人设崩塌了,我倒觉得与其将动画观感差归咎于江师姐的人设崩塌,倒不如说是人设与故事逻辑不兼容和细节填充征服者康死了吗?蚁人3导演作出回应目前,漫威电影蚁人与黄蜂女量子狂潮(简称蚁人3)上映差不多也有10天时间了。相信平时关注漫威的粉丝,基本上都已经看过这部电影。在蚁人3正片结局,征服者康的高科技装备由于遭到千万只蚂老年人走路腿软无力是怎么回事老年人走路腿软无力一般是由于气虚血虚阳虚等原因引起的,建议老人及时就医,进行相应的治疗。1气虚是指由于元气不足引起的一系列表现,主要症状有身体虚弱面色苍白呼吸短促手脚无力发懒头晕动比肉还补!5分钟上桌,补足蛋白质!春天长个子,多给孩子吃!江南的春天,小雨淅沥,尤其早晚凉飕飕的,感觉甚至比冬天还冷!真心不想早起,可是,娃开学了学生娃的早餐,就喜欢这种不用发酵,搅拌搅拌直接就可以搞定的款式!不仅蛋白质丰富,5分钟就能上宫保鸡丁这样做才好吃,鸡肉鲜嫩,酸甜微辣,开胃下饭又下酒头条创作挑战赛人们常说没有什么事情是一顿美食解决不了的,如果有,那就再吃两顿,虽然说得有些夸张,但确实美食是每个人都抵挡不了的。不论生活中遇到什么烦恼,美食都是人们最好的慰藉,味蕾诺基亚近60年来首次换Logo标志性蓝色消失,摆脱手机厂商形象诺基亚推出全新Logo。当地时间2月26日,在巴塞罗那举行的世界移动通信大会期间,曾经的手机巨头诺基亚宣布更换其企业标识,以便重塑以往手机生产者的印象。这是该公司在近60年来首次更表现越来越稳定,勇士在今年夏天应该很难再留住这位后场大将了?在今日的一场NBA常规赛中,主场作战的金州勇士末节发力以109比104逆转战胜了明尼苏达森林狼。本场比赛后,拿下了两连胜的勇士的战绩提升到了31胜30负,排名也上升到了西部第7位而人间草木最情深只知道汪曾祺是一个非常雅致的人,但是并不是特别喜欢其作品,没有共鸣产生,怎么也读不进去。但是这天翻看网络的时候,突然看到一句话如果你来访我,我不在,请和我门外的花坐一会儿,它们很温富文此刻便是人间好时节来源淳安融媒体中心阳光洒落的日子带来了一丝春的气息清风拂过雪坑的农院里飘散出阵阵沁人心脾的梅花香在花间的树梢上挂上盏盏红灯笼红与白的点缀相伴让阖家团圆的小院多了几分心驰神往梅花是冬如何唤醒倦怠熬夜肌?假期结束开工已经有一段时间了,放假时不规律的作息和油腻的饮食让我们的皮肤状态非常不稳定,加上工作后的熬夜加班和不健康的外卖让很多姐妹都出现了各种皮肤问题。所以如何根据皮肤问题选择合