1、当主键Id命名不是“id”时,应该显式地将自定义的id指出来
例如:
Db.deleteById("post_user","user_id", 5);
2、声明式事务实现方式为拦截器
例如:
1 @Override 2 public void configInterceptor(Interceptors me) { 3 // TODO Auto-generated method stub 4 // 声明式事务 5 // actionKey 正则 实现方式---拦截器 6 me.add(new TxByActionKeyRegex("/user.*")); 7 // actionKeys 8 me.add(new TxByActionKeys("/user/save","/user/testDb")); 9 // actionMethods 10 me.add(new TxByMethods("save","update")); 11 // action methodRegex 12 me.add(new TxByMethodRegex("(.*save.*|.*update.*)")); 13 14 }
MySqlMySqlMySqlMySql 数据库表必须设置为 InnoDBInnoDB InnoDB 引擎时才支持事务, 引擎时才支持事务, MyISAMMyISAMMyISAM 并不支持事务。
3、复合主键
当一个字段无法确定唯一性的时候,需要其他字段来一起形成唯一性。就是说用来组成唯一性的字段如果有多个就是联合主键
例如:
学生成绩(学号,课程号,成绩)
那学号和课程号就可以做为联合主键.
因为学号和课程号决定了成绩.也就是说.你要知道成绩..你就要知道学号,知道学号,但还不能知道某一科的成绩.还要知道课程号.
所以函数依赖关系是{学号,课程号}->{成绩}
JFinal中复合主键实现:
<1>.
arp.addMapping("post_user", "user_id,user_class_id",User.class);
<2>.
1 // 复合主键 select * from "post_user" where "user_id" = ? and "user_class_id" = ? 2 user = Db.findById("post_user", "user_id,user_class_id",33,1); 3 System.out.println("测试复合主键:"+user.getStr("user_password"));
4、缓存
CacheInterceptor可以将action所需要的数据全部缓存下来,下次请求来时如果cache存在则直接使用数据并render,而不去调用action,
这样可以使action完全不受cache相关代码污染,即插即用。
示例代码如下:
1 // 测试缓存 需要在ehcache.xml 中进行配置 例如:<cache name="/user/testCache"...> 2 @Before(CacheInterceptor.class) 3 public void testCache() { 4 System.out.println("测试Cache"); 5 String sql = "select * from post_user u inner join post_class c on u.user_class_id = c.class_id" 6 + " where u.user_name= ?"; 7 User user = User.user.findFirst(sql,"liubaohua"); 8 9 System.out.println("多表关联-操作成功!"+" 学生:" 10 +user.getStr("user_name")+"所在班级是:"+user.getStr("class_name")); 11 // 传参 12 setAttr("userName", user.getStr("user_name")); 13 setAttr("userClass", user.getStr("class_name")); 14 15 renderJsp("/login.jsp"); 16 }
ps: 需要在ehcache.xml 中进行配置 例如:<cache name="/user/testCache"...>
方式二:使用注解
// 使用注解的方式,取代默认的actionKey作为actionName 需要在ehcache.xml 中进行配置 例如:<cache name="testCache"...>
@CacheName("testCache")
清除缓存:
1 /** 2 * EvictInterceptor可以根据CacheName注解自动清除缓存 3 */ 4 @Before(EvictInterceptor.class) 5 @CacheName("testCache") 6 public void testEvict() { 7 8 redirect("login.html"); 9 }
5、forward内部跳转 和redirect重定向跳转的区别(面试经常被问到)
<1>.从地址栏显示来说
forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址.
redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.
<2>.从数据共享来说
forward:转发页面和转发到的页面可以共享request里面的数据.
redirect:不能共享数据.
<3>.从运用地方来说
forward:一般用于用户登陆的时候,根据角色转发到相应的模块.
redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等.
<4>.从效率来说
forward:高.
redirect:低.
6、CacheKit 缓存操作工具
示例如下:
1 /** 2 * CacheKit 是缓存操作工具类 3 */ 4 public void testCacheKit() { 5 final String sql = "select * from post_user u inner join post_class c on u.user_class_id = c.class_id" 6 + " where u.user_name= ?"; 7 // 从缓存中取出 8 User user = CacheKit.get("testCache", "user"); 9 if(user == null) { 10 user = User.user.findFirst(sql,"张三丰"); 11 // 放入到缓存 12 CacheKit.put("testCache", "user",user); 13 } 14 setAttr("userName", user.getStr("user_name")); 15 setAttr("userClass", user.getStr("class_name")); 16 17 render("/login.html"); 18 19 /** 20 *CacheKit重载CacheKit.get(String,String,IDataLoader)方法示例 21 * 22 * CacheKit.get方法提供一个IDataLoader接口,该接口中的load方法在缓存不存在时才会被调用 23 * 24 */ 25 user = CacheKit.get("testCache", "user",new IDataLoader() { 26 27 public Object load() { 28 // TODO Auto-generated method stub 29 return User.user.findFirst(sql,"张三丰"); 30 } 31 }); 32 33 } 34
35