wang123

2009年3月23日

Hibernate Shard简介介绍

HibernateShard
    多数据库水平分区解决方案。

1. 简介
     Hibernate 的一个扩展,用于处理多数据库水平分区架构。
     由google工程师 2007年 捐献给 Hibernate社区。 
     http://www.hibernate.org/414.html
     目前版本:   3.0.0 beta2, 未发GA版。
     条件:Hibernate Core 3.2, JDK 5.0

2. 水平分区原理
     一个库表如 Order 存在于多个数据库实例上。按特定的分区逻辑,将该库表的数据存储在这些实例中,一条记录的主键 PK,在所有实例中不得重复。
   
    水平分区在大型网站,大型企业应用中经常采用。 像www.sina.com.cn ,www.163.com  www.bt285.cn www.guihua.org
    目的出于海量数据分散存储,分散操作,分散查询以便提高数据处理量和整体数据处理性能。
  
    使用:
      google工程师的设计还是非常好的,完全兼容 Hibernate本身的主要接口。
Java代码 复制代码
  1. org.hibernate.Session   
  2. org.hibernate.SessionFactory    
  3.  org.hibernate.Criteria    
  4.  org.hibernate.Query   

     因此程序员开发变化不大,甚至不需要关心后台使用了分区数据库。程序迁移问题不大。而且配置上比较简明。

3. 三种策略:
   1) ShardAccessStrategy, 查询操作时,到那个分区执行。
      默认提供两个实现:
      顺序策略:SequentialShardAccessStrategy, 每个query按顺序在所有分区上执行。
      平行策略:ParallelShardAccessStrategy, 每个query以多线程方式并发平行的在所有分区上执行。 此策略下,需要使用线程池机制满足特定的性能需要,java.util.concurrent.ThreadPoolExecutor。

   2) ShardSelectionStrategy, 新增对象时,存储到哪个分区。
         框架默认提供了一个轮询选择策略 RoundRobinShardSelectionStrategy, 但一般不这样使用。
        通常采用“attribute-based sharding”机制,基于属性分区。一般是用户根据表自己实现一个基于属性分区的策略类ShardSelectionStrategy ,例如,以下WeatherReport基于continent属性选择分区:
Java代码 复制代码
  1.   public class WeatherReportShardSelectionStrategy implements ShardSelectionStrategy {   
  2. public ShardId selectShardIdForNewObject(Object obj) {   
  3.     if(obj instanceof WeatherReport) {   
  4.         return ((WeatherReport)obj).getContinent().getShardId();   
  5.     }   
  6.     throw new IllegalArgumentException();   
  7. }   

 

   3) ShardResolutionStrategy, 该策略用于查找单个对象时,判断它在哪个或哪几个分区上。
      默认使用 AllShardsShardResolutionStrategy ,可以自定义例如:
Java代码 复制代码
  1. public class WeatherReportShardResolutionStrategy extends AllShardsShardResolutionStrategy {   
  2.     public WeatherReportShardResolutionStrategy(List<ShardId> shardIds) {   
  3.         super(shardIds);   
  4.     }   
  5.   
  6.     public List<ShardId> selectShardIdsFromShardResolutionStrategyData(   
  7.             ShardResolutionStrategyData srsd) {   
  8.         if(srsd.getEntityName().equals(WeatherReport.class.getName())) {   
  9.             return Continent.getContinentByReportId(srsd.getId()).getShardId();   
  10.         }   
  11.         return super.selectShardIdsFromShardResolutionStrategyData(srsd);   
  12.     }   
  13. }  



4. 水平分区下的查询

   对于简单查询 HibernateShard 可以满足。

   水平分区下多库查询是一个挑战。主要存在于以下三种操作:
   1) distinct
         因为需要遍历所有shard分区,并进行合并判断重复记录。
   2) order by
         类似 1)
   3) aggregation
         count,sim,avg等聚合操作先分散到分区执行,再进行汇总。
         是不是有点类似于 MapReduce ? 呵呵。
  
   目前 HibernateShard 不支持 1), 2), 对 3) 部分支持

    HibernateShard 目前通过 Criteria 接口的实现对 聚合提供了较好的支持, 因为 Criteria 以API接口指定了 Projection 操作,逻辑相对简单。

    而HQL,原生 SQL 还不支持此类操作。

    
5. 再分区和虚拟分区
      当数据库规模增大,需要调整分区逻辑和数据存储时, 需要再分区。
      两种方式: 1)数据库数据迁移其他分区; 2) 改变记录和分区映射关系。这两种方式都比较麻烦。尤其“改变记录和分区映射关系”,需要调整 ShardResolutionStrategy。

     HibernateShard 提供了一种虚拟分区层。当需要调整分区策略时,只需要调整虚拟分区和物理分区映射关系即可。以下是使用虚拟分区时的配置创建过程:

Java代码 复制代码
  1.     
  2.   Map<Integer, Integer> virtualShardMap = new HashMap<Integer, Integer>();   
  3. virtualShardMap.put(00);   
  4. virtualShardMap.put(10);   
  5. virtualShardMap.put(21);   
  6. virtualShardMap.put(31);   
  7. ShardedConfiguration shardedConfig =   
  8.     new ShardedConfiguration(   
  9.         prototypeConfiguration,   
  10.         configurations,   
  11.         strategyFactory,   
  12.         virtualShardMap);   
  13. return shardedConfig.buildShardedSessionFactory();  


6.  局限:
    1)HibernateShard 不支持垂直分区, 垂直+水平混合分区。

    2) 水平分区下 查询功能受到一定限制,有些功能不支持。实践中,需要在应用层面对水平分区算法进行更多的考虑。
    3) 不支持跨分区的 关系 操作。例如:删除A分区上的 s 表,B分区上的关联子表 t的记录无法进行参照完整性约束检查。 (其实这个相对 跨分区查询的挑战应该说小的多,也许google工程师下个版本会支持,呵呵)

    4) 解析策略接口似乎和对象ID全局唯一性有些自相矛盾,
AllShardsShardResolutionStrategy 的接口返回的是给定对象ID所在的 shard ID集合,按理应该是明确的一个 shard ID.

参考资料:HibernateShard 参考指南。

posted @ 2009-04-01 18:49 王| 编辑 收藏

GPS经纬度可以用来Java解析

现在正开发的定位模块用到的定位设置是塞格车圣导航设备,发送指令返回的经纬度需要转换成十进制,再到GIS系统获取地理信息描述。以后需要要经常用到这方面的知识,随笔写下。

 

将经纬度转换成十进制

 公式:
    Decimal Degrees = Degrees + minutes/60 + seconds/3600
  例:57°55'56.6" =57+55/60+56.6/3600=57.9323888888888
 
如把经纬度  (longitude,latitude) (205.395583333332,57.9323888888888)转换据成坐标(Degrees,minutes,seconds)(205°23'44.1",57°55'56.6")。
步骤如下:

1、 直接读取"度":205

2、(205.395583333332-205)*60=23.734999999920 得到"分":23

3、(23.734999999920-23)*60=44.099999995200 得到"秒":44.1

 

发送定位指令,终端返回的经纬度信息如下:

(ONE072457A3641.2220N11706.2569E000.000240309C0000400)

按照协议解析

 

获得信息体的经纬度是主要,其它不要管,直接用String类的substring()方法截掉,获取的经纬度

3641.2220N11706.2569E http://www.bt285.cn

Java代码 复制代码
  1. package com.tdt.test;   
  2.   
  3. import com.tdt.api.gis.LocationInfo;   
  4.   
  5. /**  
  6.  * <p>Title:坐标转换 </p>  
  7.  *   
  8.  * <p>Description:</p>  
  9.  *   
  10.  * <p>Copyright: Copyright (c) 2009</p>  
  11.  *   
  12.  * <p>Company:</p>  
  13.  *   
  14.  * @author sunnylocus  
  15.  * @version 1.0 [2009-03-24]  
  16.  *   
  17.  */  
  18. public class LonlatConversion {   
  19.   
  20.     /**  
  21.      *   
  22.      * @param dms 坐标  
  23.      * @param type 坐标类型  
  24.      * @return String 解析后的经纬度  
  25.      */  
  26.     public static String xypase(String dms, String type) {   
  27.         if (dms == null || dms.equals("")) {   
  28.             return "0.0";   
  29.         }   
  30.         double result = 0.0D;   
  31.         String temp = "";   
  32.            
  33.         if (type.equals("E")) {//经度   
  34.             String e1 = dms.substring(03);//截取3位数字,经度共3位,最多180度   
  35.                                             //经度是一伦敦为点作南北两极的线为0度,所有往西和往东各180度    
  36.             String e2 = dms.substring(3, dms.length());//需要运算的小数   
  37.   
  38.             result = Double.parseDouble(e1);   
  39.             result += (Double.parseDouble(e2) / 60.0D);   
  40.             temp = String.valueOf(result);   
  41.             if (temp.length() > 9) {   
  42.                 temp = e1 + temp.substring(temp.indexOf("."), 9);   
  43.             }   
  44.         } else if (type.equals("N")) {      //纬度,纬度是以赤道为基准,相当于把地球分两半,两个半球面上的点和平面夹角0~90度   
  45.             String n1 = dms.substring(02);//截取2位,纬度共2位,最多90度   
  46.             String n2 = dms.substring(2, dms.length());   
  47.   
  48.             result = Double.parseDouble(n1);   
  49.             result += Double.parseDouble(n2) / 60.0D;   
  50.             temp = String.valueOf(result);   
  51.             if (temp.length() > 8) {   
  52.                 temp = n1 + temp.substring(temp.indexOf("."), 8);   
  53.             }   
  54.         }   
  55.         return temp;   
  56.     }   
  57.     public static void main(String[] args) {   
  58.         String info="(ONE072457A3641.2220N11706.2569E000.000240309C0000400)";           
  59.         info=info.substring(11,info.length()-13);   
  60.         //纬度   
  61.         String N = info.substring(0, info.indexOf("N"));   
  62.         //经度   
  63.         String E = info.substring(info.indexOf("N")+1,info.indexOf("E"));   
  64.         //请求gis,获取地理信息描述   
  65.         double x = Double.parseDouble(CoordConversion.xypase(E,"E"));   
  66.         double y = Double.parseDouble(CoordConversion.xypase(N,"N"));   
  67.         String result =LocationInfo.getLocationInfo("test", x, y); //System.out.println("径度:"+x+","+"纬度:"+y);   
  68.         System.out.println(result);   
  69.     }   
  70. }  

运行结果

在济南市,位于轻骑路和八涧堡路附近;在环保科技园国际商务中心和济南市区贤文庄附近。

posted @ 2009-03-26 17:08 王| 编辑 收藏

用Java来显示图片生成器

一、本图片生成器具有以下功能特性:

     1、可以设置图片的宽度、高度、外框颜色、背景色;

     2、可以设置图片字体的大小、名称、颜色;

     3、可以设置输出图片的格式,如JPEG、GIF等;

     4、可以将图片存储到一个文件或者存储到一个输出流;

     5、可以为图片增加若干条干扰线(在生成随机码图片时可用此特性);

     6、打印在图片上的文字支持自动换行;

 

另外,本图片生成器还用到了模板方法模式。

 

二、下面列出相关的源代码

     1、抽象类AbstractImageCreator的源代码

 /**本代码在 http://www.bt285.cn  http://www.5a520.cn 已使用了 */
  1. public abstract class AbstractImageCreator {   
  2.     private static Random rnd = new Random(new Date().getTime());   
  3.        
  4.     //图片宽度   
  5.     private int width = 200;   
  6.        
  7.     //图片高度   
  8.     private int height = 80;   
  9.        
  10.     //外框颜色   
  11.     private Color rectColor;   
  12.        
  13.     //背景色   
  14.     private Color bgColor;   
  15.        
  16.     //干扰线数目   
  17.     private int lineNum = 0;   
  18.        
  19.     //图片格式   
  20.     private String formatName = "JPEG";   
  21.        
  22.     //字体颜色   
  23.     private Color fontColor = new Color(000);   
  24.        
  25.     //字体名称   
  26.     private String fontName = "宋体";   
  27.        
  28.     //字体大小   
  29.     private int fontSize = 15;   
  30.        
  31.   
  32.     //##### 这里省略成员变脸的get、set方法 #####   
  33.   
  34.   
  35.     /**  
  36.      * 画干扰线  
  37.      */  
  38.     private void drawRandomLine(Graphics graph){   
  39.         for(int i=0;i<lineNum;i++){   
  40.             //线条的颜色   
  41.             graph.setColor(getRandomColor(100155));   
  42.                
  43.             //线条两端坐标值   
  44.             int x1 = rnd.nextInt(width);   
  45.             int y1 = rnd.nextInt(height);   
  46.                
  47.             int x2 = rnd.nextInt(width);   
  48.             int y2 = rnd.nextInt(height);   
  49.                
  50.             //画线条   
  51.             graph.drawLine(x1, y1, x2, y2);   
  52.         }   
  53.     }   
  54.        
  55.     /**  
  56.      * 随机获取颜色对象  
  57.      */  
  58.     private Color getRandomColor(int base, int range){   
  59.         if((base + range) > 255) range = 255 - base;   
  60.            
  61.         int red = base + rnd.nextInt(range);   
  62.         int green = base + rnd.nextInt(range);   
  63.         int blue = base + rnd.nextInt(range);   
  64.            
  65.         return new Color(red, green, blue);   
  66.     }   
  67.            
  68.                 //该方法内应用了模板方法模式   
  69.     public void drawImage(String text)throws IOException{   
  70.         BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);   
  71.            
  72.         if(rectColor == null) rectColor = new Color(000);   
  73.         if(bgColor == null) bgColor = new Color(240251200);   
  74.            
  75.         //获取画布   
  76.         Graphics graph = image.getGraphics();   
  77.            
  78.         //画长方形   
  79.         graph.setColor(bgColor);   
  80.         graph.fillRect(00, width, height);   
  81.            
  82.         //外框   
  83.         graph.setColor(rectColor);   
  84.         graph.drawRect(00, width-1, height-1);   
  85.            
  86.         //画干扰线   
  87.         drawRandomLine(graph);   
  88.            
  89.         //画字符串   
  90.         drawString(graph, text);   
  91.            
  92.         //执行   
  93.         graph.dispose();   
  94.            
  95.         //输出图片结果   
  96.         saveImage(image);   
  97.     }   
  98.        
  99.     protected abstract void drawString(Graphics graph, String text);   
  100.        
  101.     protected abstract void saveImage(BufferedImage image)throws IOException;   
  102.        
  103. }  

 

     2、类DefaultImageCreator的源代码

          该类将生成的图片存储到一个文件中,需要设置outputFilePath成员变量值,该成员变量值表示图片的存储全路径。

Java代码 复制代码
  1. public class DefaultImageCreator extends AbstractImageCreator {   
  2.     private String outputFilePath;   
  3.        
  4.     public String getOutputFilePath() {   
  5.         return outputFilePath;   
  6.     }   
  7.   
  8.     public void setOutputFilePath(String outputFilePath) {   
  9.         this.outputFilePath = outputFilePath;   
  10.     }   
  11.        
  12.     public DefaultImageCreator(){   
  13.            
  14.     }   
  15.        
  16.     public DefaultImageCreator(String outputFilePath){   
  17.         this.outputFilePath = outputFilePath;   
  18.     }   
  19.   
  20.     @Override  
  21.     protected void drawString(Graphics graph, String text) {   
  22.         graph.setColor(getFontColor());   
  23.         Font font = new Font(getFontName(), Font.PLAIN, getFontSize());   
  24.         graph.setFont(font);   
  25.            
  26.         FontMetrics fm = graph.getFontMetrics(font);   
  27.         int fontHeight = fm.getHeight(); //字符的高度   
  28.            
  29.         int offsetLeft = 0;   
  30.         int rowIndex = 1;   
  31.         for(int i=0;i<text.length();i++){   
  32.             char c = text.charAt(i);   
  33.             int charWidth = fm.charWidth(c); //字符的宽度   
  34.   
  35.             //另起一行   
  36.             if(Character.isISOControl(c) || offsetLeft >= (getWidth()-charWidth)){   
  37.                 rowIndex++;   
  38.                 offsetLeft = 0;   
  39.             }   
  40.                
  41.             graph.drawString(String.valueOf(c), offsetLeft, rowIndex * fontHeight);   
  42.             offsetLeft += charWidth;   
  43.         }   
  44.     }   
  45.        
  46.     @Override  
  47.     protected void saveImage(BufferedImage image)throws IOException{   
  48.         ImageIO.write(image, getFormatName(), new File(outputFilePath));   
  49.     }   
  50.   
  51. }  

 

     3、类OutputStreamImageCreator的源代码

         该类将生成的图片存储到一个输出流中,需要设置out成员变量值。

Java代码 复制代码
  1. public class OutputStreamImageCreator extends DefaultImageCreator {   
  2.     private OutputStream out ;   
  3.        
  4.     public OutputStream getOut() {   
  5.         return out;   
  6.     }   
  7.   
  8.     public void setOut(OutputStream out) {   
  9.         this.out = out;   
  10.     }   
  11.        
  12.     public OutputStreamImageCreator(){   
  13.            
  14.     }   
  15.        
  16.     public OutputStreamImageCreator(OutputStream out){   
  17.         this.out = out;   
  18.     }   
  19.   
  20.     @Override  
  21.     public String getOutputFilePath() {   
  22.         return null;   
  23.     }   
  24.   
  25.     @Override  
  26.     public void setOutputFilePath(String outputFilePath) {   
  27.         outputFilePath = null;   
  28.     }   
  29.   
  30.     @Override  
  31.     protected void saveImage(BufferedImage image) throws IOException {   
  32.         if(out!=null) ImageIO.write(image, getFontName(), out);   
  33.     }   
  34.        
  35. }  

 

三、实例代码

     1、图片存储到文件

StringBuffer sb = new StringBuffer();   
  1. sb.append("中华人民共和国\n");   
  2. sb.append("中华人民共和国\n");   
  3.   
  4. DefaultImageCreator creator = new DefaultImageCreator("c:\\img.jpeg");   
  5. creator.setWidth(150);   
  6. creator.setHeight(100);   
  7. creator.setLineNum(60);   
  8. creator.setFontSize(20);   
  9. creator.drawImage(sb.toString());  

 

posted @ 2009-03-23 18:49 王| 编辑 收藏

<2009年3月>
22232425262728
1234567
891011121314
15161718192021
22232425262728
2930311234

导航

统计

常用链接

留言簿(3)

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜