Category:学习笔记’

Hibernate关联映射

 - by wu shengyuan

以简单的两个类为例:
User(int id, String name)
Group(int id, String name)

没有关联关系时的关系模型:
t_user(id int pk, name varchar)
t_group(id int pk, name varchar)

一、多对一和一对多关联映射(多个用户有相同的组)

这几种关联映射后的关系模型是相同的:
t_user(id int pk, name varchar, gid int fk->t_group(id))
t_group(id int pk, name varchar)

1、多对一单向关联

实体模型:
bean.User(int id, String name, Group group)
bean.Group(int id, String name)

<!-- bean/User.hbm.xml -->
<hibernate-mapping>
    <class name="bean.User" table="t_user">
        <id name="id"><generator class="native"/></id>
        <property name="name"/>
        <!-- 使用<many-to-one>映射多对一关系。导出ddl时将自动生成一个外键 -->
        <many-to-one name="group" column="gid"/>
    </class>
</hibernate-mapping>
<!-- bean/Group.hbm.xml -->
<hibernate-mapping>
    <class name="bean.Group" table="t_group">
        <id name="id"><generator class="native"/></id>
        <property name="name"/>
    </class>
</hibernate-mapping>
2、一对多单向关联(几乎不用)

实体模型:
bean.User(int id, String name)
bean.Group(int id, String name, Set users)

<!-- bean/User.hbm.xml -->
<hibernate-mapping>
    <class name="bean.User" table="t_user">
        <id name="id"><generator class="native"/></id>
        <property name="name"/>
    </class>
</hibernate-mapping>
<!-- bean/Group.hbm.xml -->
<hibernate-mapping>
    <class name="bean.Group" table="t_group">
        <id name="id"><generator class="native"/></id>
        <property name="name"/>
        <!-- 使用<set>映射集合 -->
        <set name="users">
            <!-- 使用<key>指定引用至自身的外键表(t_user)中的外键 -->
            <key column="gid"/>
            <!-- 使用<one-to-many>映射一对多关系 -->
            <one-to-many class="bean.User"/>
        </set>
    </class>
</hibernate-mapping>

为Group加入集合也可以使用List(<list>),注意不能指定类型是具体的HashSet或ArrayList,只能是接口Set或List。
集合标签可以使用order-by属性指定排序:

<set name="users" order-by="id desc">
3、双向关联

实体模型:
bean.User(int id, String name, Group group)
bean.Group(int id, String name, Set users)

<!-- bean/User.hbm.xml -->
<hibernate-mapping>
    <class name="bean.User" table="t_user">
        <id name="id"><generator class="native"/></id>
        <property name="name"/>
        <!-- 使用<many-to-one>映射多对一关系。导出ddl时将自动生成一个外键 -->
        <many-to-one name="group" column="gid"/>
    </class>
</hibernate-mapping>
<!-- bean/Group.hbm.xml -->
<hibernate-mapping>
    <class name="bean.Group" table="t_group">
        <id name="id"><generator class="native"/></id>
        <property name="name"/>
        <!-- 使用<set>映射集合 -->
        <set name="users">
            <!-- 使用<key>指定引用至自身的外键表(t_user)中的外键 -->
            <key column="gid"/>
            <!-- 使用<one-to-many>映射一对多关系 -->
            <one-to-many class="bean.User"/>
        </set>
    </class>
</hibernate-mapping>

双向关联中,为<set>加入”inverse=true”可以反转维护关系:Hibernate将放弃从一的一端维护。意思就是user和group的关系必须使用user维护,操作group时Hibernate将不维护这个关系。

<set name="users" inverse="true">

操作group的示例:

            session.beginTransaction();
            User user = new User();
            user.setName("张三");
            Group group = new Group();
            group.setName("admin");
            group.setUsers(new HashSet());
            group.getUsers().add(user);
            session.save(user);
            session.save(group);
            session.getTransaction().commit();

没有配置inverse=”true”时,Hibernate输出了添加user和group,并更新user的语句:

Hibernate: insert into t_user (name, gid) values (?, ?)
Hibernate: insert into t_group (name) values (?)
Hibernate: update t_user set gid=? where id=?
而配置了inverse=”true”后,Hibernate仅仅输出了添加user和group的语句,并没有更新user,放弃了关系的维护:
Hibernate: insert into t_user (name, gid) values (?, ?)
Hibernate: insert into t_group (name) values (?)
此时应该从user端维护关系:
            session.beginTransaction();
            Group group = new Group();
            group.setName("admin");
            User user = new User();
            user.setName("张三");
            user.setGroup(group);
            session.save(group);
            session.save(user);
            session.getTransaction().commit();

因为外键列在t_user表中,从group端维护需要操作多表,所以从user端维护关系更加合理,效率也更高。上面的代码输出两条SQL语句,插入数据的同时也维护了关系:

Hibernate: insert into t_group (name) values (?)
Hibernate: insert into t_user (name, gid) values (?, ?)

 

二、一对一关联映射(每个用户独有一个组)

依照映射方法不同,可分为主键关联映射唯一外键关联映射。主键关联是维护两张表的主键一致,如有必要还可以在主键上再加上外键约束;唯一外键关联则类似于多对一关联,为表加入一个外键列,不过一对一关联会同时将这个外键加上唯一约束。

1、主键关联映射

主键关联生成的关系模型:
t_user(id int pk fk->t_group(id), name varchar)
t_group(id int pk, name varchar)

1.1、主键单向关联

实体模型:
bean.User(int id, String name, Group group)
bean.Group(int id, String name)

<!-- bean/User.hbm.xml -->
<hibernate-mapping>
    <class name="bean.User" table="t_user">
        <id name="id">
            <!-- 指定主键生成策略为外键 -->
            <generator class="foreign">
                <!-- 指定要参照的属性 -->
                <param name="property">group</param>
            </generator>
        </id>
        <property name="name"/>
        <!-- 使用<one-to-one>映射一对一关系。 -->
        <one-to-one name="group">
    </class>
</hibernate-mapping>
<!-- bean/Group.hbm.xml -->
<hibernate-mapping>
    <class name="bean.Group" table="t_group">
        <id name="id"><generator class="native"/></id>
        <property name="name"/>
    </class>
</hibernate-mapping>

主键关联由Hibernate维护,不依赖数据库。如果需要在数据库端也生成外键约束,可以使用constrained:

<one-to-one name="group" constrained="true"/>

1.2、主键双向关联

实体模型:
bean.User(int id, String name, Group group)
bean.Group(int id, String name, User user)

<!-- bean/User.hbm.xml -->
<hibernate-mapping>
    <class name="bean.User" table="t_user">
        <id name="id">
            <!-- 指定主键生成策略为外键 -->
            <generator class="foreign">
                <!-- 指定要参照的属性 -->
                <param name="property">group</param>
            </generator>
        </id>
        <property name="name"/>
        <!-- 使用<one-to-one>映射一对一关系。 -->
        <one-to-one name="group">
    </class>
</hibernate-mapping>
<!-- bean/Group.hbm.xml -->
<hibernate-mapping>
    <class name="bean.Group" table="t_group">
        <id name="id"><generator class="native"/></id>
        <property name="name"/>
        <!-- 使用<one-to-one>映射一对一关系 -->
        <one-to-one name="user"/>
    </class>
</hibernate-mapping>

 

2、唯一外键关联映射

唯一外键关联生成的关系模型:
t_user(id int pk, name varchar, gid int fk->t_group(id))
t_group(id int pk, name varchar)

2.1、唯一外键单向关联

实体模型:
bean.User(int id, String name, Group group)
bean.Group(int id, String name)

<!-- bean/User.hbm.xml -->
<hibernate-mapping>
    <class name="bean.User" table="t_user">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <!-- 为<many-to-one>加上unique就变成了一对一 -->
        <many-to-one name="group" unique="true" column="gid"/>
    </class>
</hibernate-mapping>
<!-- bean/Group.hbm.xml -->
<hibernate-mapping>
    <class name="bean.Group" table="t_group">
        <id name="id"><generator class="native"/></id>
        <property name="name"/>
    </class>
</hibernate-mapping>

2.2、唯一外键双向关联

实体模型:
bean.User(int id, String name, Group group)
bean.Group(int id, String name, User user)

<!-- bean/User.hbm.xml -->
<hibernate-mapping>
    <class name="bean.User" table="t_user">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <!-- 为<many-to-one>加上unique就变成了一对一 -->
        <many-to-one name="group" unique="true" column="gid"/>
    </class>
</hibernate-mapping>
<!-- bean/Group.hbm.xml -->
<hibernate-mapping>
    <class name="bean.Group" table="t_group">
        <id name="id"><generator class="native"/></id>
        <property name="name"/>
        <!-- 使用<one-to-one>映射一对一 -->
        <one-to-one name="user"/>
    </class>
</hibernate-mapping>

三、多对多关联映射(每个用户拥有多个组,每个组也有多个用户)

多对多关联映射关系使用中间表表示。导出关系模型时Hibernate将自动生成复合主键以及外键约束。

关系模型:
t_user(id int pk, name varchar)
t_group(id int pk, name varchar)
t_user_group(userid int fk->t_user(id), groupid int fk->t_group(id), pk(userid, groupid))

1、多对多单向关联

实体模型:
bean.User(int id, String name, Set groups)
bean.Group(int id, String name)

<!-- bean/User.hbm.xml -->
<hibernate-mapping>
    <class name="bean.User" table="t_user">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <!-- 使用<set>映射集合,在多对多关系中,Hibernate将生成第三张表 -->
        <set name="groups" table="t_user_group">
            <!-- 使用<key>指定引用至自身的外键表(t_user_group)中的外键 -->
            <key column="userid"/>
            <!-- 使用<many-to-many>映射多对多关系,column指定另一端在表t_user_group中的列 -->
            <many-to-many class="bean.Group" column="groupid"/>
        </set>
    </class>
</hibernate-mapping>
<!-- bean/Group.hbm.xml -->
<hibernate-mapping>
    <class name="bean.Group" table="t_group">
        <id name="id"><generator class="native"/></id>
        <property name="name"/>
    </class>
</hibernate-mapping>
1、多对多单向关联

实体模型:
bean.User(int id, String name, Set groups)
bean.Group(int id, String name, Set users)

<!-- bean/User.hbm.xml -->
<hibernate-mapping>
    <class name="bean.User" table="t_user">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <!-- 使用<set>映射集合,在多对多关系中,Hibernate将生成第三张表 -->
        <set name="groups" table="t_user_group">
            <!-- 使用<key>指定引用至自身的外键表(t_user_group)中的外键 -->
            <key column="userid"/>
            <!-- 使用<many-to-many>映射多对多关系,column指定另一端在表t_user_group中的列 -->
            <many-to-many class="bean.Group" column="groupid"/>
        </set>
    </class>
</hibernate-mapping>
<!-- bean/Group.hbm.xml -->
<hibernate-mapping>
    <class name="bean.Group" table="t_group">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <!-- 使用<set>映射集合,在多对多关系中,Hibernate将生成第三张表 -->
        <set name="users" table="t_user_group">
            <!-- 使用<key>指定引用至自身的外键表(t_user_group)中的外键 -->
            <key column="groupid"/>
            <!-- 使用<many-to-many>映射多对多关系,column指定另一端在表t_user_group中的列 -->
            <many-to-many class="bean.User" column="userid"/>
        </set>
    </class>
</hibernate-mapping>

多对多的双向关联同样可以在不想要维护关系的一端的<set>里设置inverse=”true”;但是必须有一端可以维护,也就是说只可以设置一个。

针对移动设备web制作的小知识

 - by wu shengyuan

最近,因为对手持设备样式表的逐渐了解,我对手机网站的开发设想产生了一点点改变。

首先,什么时候你会想打开手机用来上网?

通常有两种情况:一种是急需获得某种信息,但因为各种原因只能通过手机上网查询;另一种是闲着无聊,便通过手机上网消遣。
对于后一种情况,设计一种同电脑浏览有相同浏览体验的网站依然是每一个WEB开发者的梦想,但是对于前一种呢?当上课要迟到时,在路上赶路缺忘了上课的课室时,只想快速地查到想要的数据,一点不在乎网页的用户体验;同样,在外地想查询某公司的电话号码时,我们需要的,仅仅是一个8位数的电话号码,并不要任何的视觉效果。

现在开始,我们将讨论如何制作针对前一种情况的wml。

现在正是移动web的成长期,在这个阶段,手机的功能正在变得越来越强,他们的内存甚至比早期的个人电脑还要多,但是,与所有技术的成长期一样,移动WEB的未来还有太多的变数。数百种手持设备,它们可能使用四十种不同的浏览器,而这些浏览器以不同的方式支持HTML和CSS。目前我建议在等待移动WEB成熟的时候保持简约耐心

下面列出了一些针对手持设备应该注意的地方:

  1. 让每KB都物有所值,隐藏额外的部分,使用更少更小的图像,等等,因为WEB访问是昂贵的。
  2. 要确保站点上每个有意义的图像都有替换文本,使以无图像方式查看页面的访问者不会错过任何信息。因为访问者可能会选择在不显示图像的情况下查看页面(从而加快访问速度)。
  3. 保证图像尽可能小,彻底地对站点进行测试。因为许多手机浏览器(比如UCWEB)会通过代理服务器对网站进行过滤,从而去掉手机浏览器无法处理的内容。
  4. 在栏上使用窄的外边距,最好根本不使用。不要使用浮动、绝对定位、表格(它们的内容可能以出乎意料的次序显示)和弹出窗口
  5. 避免使用固定宽度的设计。应该使用em和百分数来代替。
  6. 避免使用CSS字体属性,应该主要依靠标题标记,如h1,h2等等,来区分大标题和小标题。对于常规文本用p,对于强调部分用b或strong,尽量少用斜体。因为大多数手持浏览器只支持一种字体和最多两三种字号,支持粗体而不支持斜体(至少支持得不好)。
  7. 可以对导航条使用有编号的列表(ol)。因为手持设备对列表的支持很好。
  8. 避免使用背景图片。因为不太支持CSS的background-image属性。
  9. 一般支持CSS的color和background-color属性,应尽可能地利用,使得文本颜色和背景颜色之间的对比足够强烈,让访问者在日光下也能够看清页面上的内容。
  10. 确保站点的显示在没有加在样式表的情况下也是有意义的。测试时用尽可能多的手持设备或手持浏览器来查看站点。因为某些手持浏览器会完全忽视CSS文件(比如QQ手机浏览器居然像傻瓜似的不加载一个以上的样式表)。

开放移动web网页中的一些体会

 - by wu shengyuan

本文讲述我这两周手机web开发中的一些经验总结,我是个菜鸟,有什么地方说错了请大家帮忙指点一下~

时代在不断变迁,手机上网早已普及大众,但远远落后的,不是停滞不前的wap协议,而是花样百出的手机浏览器,手机浏览器已进入百家争鸣的状态。但是欣慰的是,现在手机浏览器存在一个共同的目标:如何让网页显示得和电脑看到的一样(即使电脑不同浏览器间也存在差别,特别是CSS3的到来)。

我们没有选择WML,而是HTML。

WAP协议是针对流量受限,屏幕大小较小,功率消耗小,运算处理速度低的小型移动终端而设计的;尽管WAP的兼容性和可扩展性好,可是人们的目标始终是:手机浏览和电脑浏览能得到一致的效果,因此,随着手机浏览器的发展,WAP必将被舍弃。
参考资料:http://www.wapforum.org/faqs/index.htm

几个测试

通过对不同机型的实测,请允许我我主观地对结果做一个简单的排序:

  1. Android自带浏览器

    1. 用户体验一流
      用过Android自带浏览器的用户应该深有体会,当你用两个手指放大网页上的图片时,不得不在心理发出惊叹,这种感觉太棒了!,字体和图片全部跟着放大,并懂得自动换行,这才是smartphone!
    2. 堪称完美的样式展示
      测试用的9种手机浏览器中,这种是网页兼容性最好的浏览器了。和我在电脑上用firefox测试的效果一模一样,甚至在某些方面做得更好;而且,这是测试的9种浏览器中两种实现了自动跳转脚本的浏览器之一。
    3. 字体显示全部按用户设定的大小显示
  2. Opera Mobile (Version 10.00)

    超炫的界面,几乎完美的兼容性,仅仅是偶尔的中文排版问题(原因不明,英文可以完美展示,中文浏览部分网站会排版错误,比如一行多出3个字符)。

  3. Symbian s60 3rd UCWEB (V7.2.2.51)

    适应屏幕模式:

    1. 强制统一了所以字体大小,包括h4~h6和p一样大,h1~h3比p大约2px。无斜体。
    2. 当字体颜色和背景颜色相同时,强制改为黑色。
    3. border-color默认为灰色。
    4. body强制有3px的margin。
    5. 不完全的无视margin和padding,默认margin为0,block元素有1px的padding-top和3px的padding-bottom,还有margin:5px 0px;但是当没有定义margin的上和下时,会出现IE典型的double margin的bug。
    6. 对于内联函数,对齐也有问题,有空截图下来。
    7. 缩放模式:字体还是统一了大小(UC这你就做得不对了)。

  4. 魅族自带浏览器

    感觉就是仿Android,可是幸运的是,“该有”的小bug它也有了~

  5. Opera Mini(Version 5.0.18755)

    作为mini型浏览器,opera mini非常的出色,几乎完美地表现了盒子模型,只是偶尔会碰到中文字体换行有偏差,估计是外框的左padding撑开了字体?不对啊,一行显示的字数足足多出了4,5个…这个以后有空在研究。

  6. Android UCWEB(v7.0.3.45) & 魅族UCWEB(v7.1.042 wince)

    不明白为什么Android的UCWEB比Symbian的效果差,字体大小被重设,这本身没有什么问题,错就错在字体被放大得太大了,图标和图片还是原比例,搭配非常不协调。还有很多小bug,比如图标对齐有问题。

  7. Symbian s60 3rd自带浏览器

    网络浏览体验其实还蛮不错的,可惜以为一尘不变以及流量的浪费,使它最后还是成为了诺基亚的一个花瓶。

  8. Symbian QQ浏览器

    请原谅这位手机浏览器的初生婴儿吧,半岁大的QQ手机浏览器,不单止只能载入单一CSS,默认字体和大小都奇丑无比,样式也一团糟,还自作聪明地去掉了所有空格,除了进QQ农场,还是不要干别的好…

一些要注意的地方:

  • 所有测试的适应屏幕浏览器均不支持a:focus。所有懂得适应屏幕模式都重设了字体大小和样式。(现在想想重设才是正常的)
  • 不要自动跳转。
  • 少用背景图片。

【字体】

  • 不要对字体抱有任何幻想,感觉比较漂亮的字体还是arial,sans-serif;
  • 字体大小虽然不是必要但是最好还是重新设定,这对于能缩放的浏览器有较好的用户体验;
  • 视觉设计不要依赖于你的字体大小和字体颜色,因为大多数浏览器会重设你的字体,包括大小和颜色

Summary

  • 对于有重写代码的css,手机浏览器对重写的优先级顺序更加复杂,建议不要写太复杂的CSS。
  • 手机浏览器兼容性相当混乱,不建议尝试制作精密到像素的手机WEB设计。
  • 如果目标只是制作手机网页,怎么简单就怎么做,不要依赖CSS达到美观效果,但可以试着多加些小gif图标。
  • 既然不同浏览器的网页展现方式如此不同,那么,最低限度请不要出现任何的html或css错误了,对代码不严密的网页,不同浏览器的纠错能力各不相同,展示效果更是“随心所欲”。