(转) Hibernate框架基础——操纵持久化对象的方法(Session中)
http://blog.csdn.net/yerenyuan_pku/article/details/52761021
上一篇文章中我们学习了Hibernate中java对象的状态以及对象的状态之间如何转换。本文我们将详细讲解Session中的方法。
save()
Session的save()方法使一个临时对象转变为持久化对象。
Session的save()方法完成以下操作:
- 把新new的对象加入到Session缓存中,使它进入持久化状态。
- 选用映射文件指定的标识符生成器,为持久化对象分配唯一的OID。在使用代理主键的情况下,setId()方法为新new的对象设置OID是无效的。
- 计划执行一条insert语句,把User对象当前的属性值组装到insert语句中。
注意:Hibernate通过持久化对象的OID来维持它和数据库相关记录的对应关系。当新new的对象处于持久化状态时, 不允许程序随意修改它的ID。
save()方法介绍完了,那就应该实践一把,毕竟实践出真知。
我们最好新建一个普通java工程,如Hibernate_Test,然后在cn.itcast.h_session_method包下新建持久化类——User.java。
public class User {
private Integer id; // 0, null 如果是数字,建议使用包装类型。
private String name;
private byte[] data = new byte[1024 * 1024 * 10];
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- 1
接着在cn.itcast.h_session_method包中创建User类对应的映射配置文件——User.hbm.xml。
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.h_session_method">
<class name="User" table="user">
<id name="id">
<generator class="native"></generator>
</id>
<property name="name" />
</class>
</hibernate-mapping>
- 1
- 2
我们应该使案例更加简洁易懂点。接着我们就要编写单元测试类来试验save()方法了。
public class App {
private static SessionFactory sessionFactory = new Configuration() //
.configure() //
.addClass(User.class) // 添加Hibernate实体类(加载对应的映射文件)
.buildSessionFactory();
@Test
public void testSave() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = new User(); // 临时状态
user.setName("test");
session.save(user); // 变为了持久化状态
user.setName("李四");
// -------------------------------------------
session.getTransaction().commit();
session.close();
System.out.println(user.getName()); // 游离状态
}
}
- 1
测试testSave()方法,数据库表记录为:
Eclipse控制台打印如下:
Hibernate: insert into user (name) values (?)
Hibernate: update user set name=? where id=?
李四
但是,若testSave()方法的代码改为:
@Test
public void testSave() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = new User(); // 临时状态
user.setName("test");
session.save(user); // 变为了持久化状态
// -------------------------------------------
session.getTransaction().commit();
session.close();
user.setName("李四");
System.out.println(user.getName()); // 游离状态
}
测试testSave()方法,数据库表记录为:
Eclipse控制台打印如下:
Hibernate: insert into user (name) values (?)
李四
save()方法是把临时状态转变为持久化状态,即把临时状态的对象放在Session缓存里面,交给Session管理,所以如下代码:
@Test
public void testSave() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = new User(); // 临时状态
user.setName("test");
session.save(user); // 变为了持久化状态
session.save(user); // 变为了持久化状态
session.save(user); // 变为了持久化状态
session.save(user); // 变为了持久化状态
session.save(user); // 变为了持久化状态
// -------------------------------------------
session.getTransaction().commit();
session.close();
user.setName("李四");
System.out.println(user.getName()); // 游离状态
}
Eclipse控制台只会打印一条insert into语句:
Hibernate: insert into user (name) values (?)
李四
注意:使用save()保存临时状态对象时,会立刻执行sql语句,而不是在事务提交的时候执行。例如,将testSave()方法的代码改为:
@Test
public void testSave() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = new User(); // 临时状态
user.setName("test");
session.save(user); // 变为了持久化状态
System.out.println("xxxxxxxxxxx");
// -------------------------------------------
session.getTransaction().commit();
session.close();
user.setName("李四");
System.out.println(user.getName()); // 游离状态
}
Eclipse控制台将打印:
Hibernate: insert into user (name) values (?)
xxxxxxxxxxx
李四
update()
Session的update()方法使一个游离对象转变为持久化对象,并且计划执行一条update语句。现在我们来试验update()方法,编写如下的testUpdate()方法:
@Test
public void testUpdate() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = (User) session.get(User.class, 1);
System.out.println(user.getName()); // 持久化状态
session.clear(); // 清空Session中所有的对象,变为游离状态
user.setName("newname"); // 更新语句只有在事务提交的时候执行
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
此时Eclipse控制台打印:
Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_ from user user0_ where user0_.id=?
李四
没有打印update语句。
但若我们将testUpdate()方法的代码修改为:
@Test
public void testUpdate() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = (User) session.get(User.class, 1);
System.out.println(user.getName()); // 持久化状态
user.setName("newname"); // 更新语句只有在事务提交的时候执行
session.clear(); // 清空Session中所有的对象,变为游离状态
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
发现Eclipse控制台仍然没有打印update语句。
Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_ from user user0_ where user0_.id=?
李四
原因是更新语句只有在事务提交的时候才执行。
但若强制更新语句马上执行,即testUpdate()方法的代码为:
@Test
public void testUpdate() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = (User) session.get(User.class, 1);
System.out.println(user.getName()); // 持久化状态
user.setName("newname"); // 更新语句只有在事务提交的时候执行
session.flush(); // 强制更新语句马上执行,刷出到数据库
session.clear(); // 清空Session中所有的对象,变为游离状态
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
此时Eclipse控制台会打印update语句。
Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_ from user user0_ where user0_.id=?
李四
Hibernate: update user set name=? where id=?
但如果testUpdate()方法的代码为:
@Test
public void testUpdate() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = (User) session.get(User.class, 1);
System.out.println(user.getName()); // 持久化状态
session.clear(); // 清空Session中所有的对象,变为游离状态
user.setName("newname2"); // 更新语句只有在事务提交的时候执行
session.flush(); // 强制更新语句马上执行,刷出到数据库
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
由于Session中的User对象变为游离状态,所以修改此状态对象时数据库不会有变化。Eclipse控制台会打印:
Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_ from user user0_ where user0_.id=?
newname
除了使用Session的clear()方法使Session中的User对象变为游离状态外,Session的evict(Object)方法同样也可以达到相同的目的。
@Test
public void testUpdate() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = (User) session.get(User.class, 1);
System.out.println(user.getName()); // 持久化状态
session.evict(user); // 清除Session中一个指定的对象
user.setName("newname2"); // 更新语句只有在事务提交的时候执行
session.flush(); // 强制更新语句马上执行,刷出到数据库
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
Eclipse控制台打印结果同上:
Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_ from user user0_ where user0_.id=?
newname
如果testUpdate()方法的代码改为:
@Test
public void testUpdate() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = (User) session.get(User.class, 1);
System.out.println(user.getName()); // 持久化状态
session.evict(user); // 清除Session中一个指定的对象
user.setName("newname2"); // 更新语句只有在事务提交的时候执行
session.update(user); // 变为了持久化状态
session.flush(); // 强制更新语句马上执行,刷出到数据库
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
此时,Eclipse控制台打印:
Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_ from user user0_ where user0_.id=?
newname
Hibernate: update user set name=? where id=?
到这里,我们做一个小结——将Session中的方法归类:
- 操作实体对象的
- save()
- update()
- saveOrUpdate()
- delete()
- 操作Session缓存的
- clear()
- evict()
- flush()
- 查询实体对象的
- get()
- load()
- createQuery()
- createCriteria()
我们把flush()拧出来说一下,flush()的作用是马上执行sql语句,但sql语句默认是在事务提交的时候执行的,事务提交的时候会先默认调用flush(),在做删除、更新时都是这样,唯独有个另外,那就是在做保存的时候。例如,将testUpdate()方法的代码改为:
@Test
public void testUpdate() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = (User) session.get(User.class, 1);
System.out.println(user.getName()); // 持久化状态
session.evict(user); // 清除Session中一个指定的对象
user.setName("newname2"); // 更新语句只有在事务提交的时候执行
session.update(user); // 变为了持久化状态
System.out.println("+++++++++++");
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
此时,Eclipse控制台打印:
Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_ from user user0_ where user0_.id=?
newname2
+++++++++++
Hibernate: update user set name=? where id=?
saveOrUpdate()
该方法同时包含save和update方法,如果参数是临时对象就用save方法,如果是游离对象就用update方法,如果是持久化对象就直接返回。也即把临时或游离状态转为持久化状态。现在我们来试验saveOrUpdate()方法,编写如下的testsaveOrUpdate()方法:
@Test
public void testSaveOrUpdate() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = new User();
user.setName("test_h");
session.saveOrUpdate(user);
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
此时,Eclipse控制台打印如下结果:
Hibernate: insert into user (name) values (?)
如果再次测试testSaveOrUpdate(),Eclipse控制台仍然会打印一条insert into语句,向数据库表中插入一条记录。
我们自己也可以模拟生成一个游离状态的对象,然后更新对象到数据库中。如下:
@Test
public void testSaveOrUpdate() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = new User();
user.setId(3); // 自己模拟生成了一个游离状态的对象,数据库中要有一个id为3的记录
user.setName("newName");
session.saveOrUpdate(user);
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
发现Eclipse控制台打印如下结果:
Hibernate: update user set name=? where id=?
理所应当地,数据库表中id为3的记录name列将变为newName。注意:数据库表中要有一个id为3的记录。如果在更新的时候,对象不存在(即数据库表中没有相应的记录)就报错,如以下代码:
@Test
public void testSaveOrUpdate() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = new User();
user.setId(300); // 自己模拟生成了一个游离状态的对象,数据库中要有一个id为3的记录
user.setName("newName");
session.saveOrUpdate(user);
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
将会报异常:org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1。
注意:本方法是根据id判断对象是什么状态的:如果id为原始值(对象是null,原始类型数字是0)就是临时状态,如果不是原始值就是游离状态。
delete()
Session的delete()方法既可以删除一个游离对象,也可以删除一个持久化对象。即把持久化或游离状态转为删除状态。
- 如果参数是持久化对象,就执行一个delete语句,若为游离对象,先使游离对象被session关联,使它变为持久化对象。
- 计划执行一条delete语句。
- 把对象从Session缓存中删除,该对象进入删除状态。
现在我们来试验delete()方法,编写如下的testDelete()方法:
@Test
public void testDelete() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = (User) session.get(User.class, 1); // 持久化状态
session.delete(user);
System.out.println("+++++++++");
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
测试testDelete()方法,会发现Eclipse控制台打印:
Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_ from user user0_ where user0_.id=?
+++++++++
Hibernate: delete from user where id=?
若将testDelete()方法的代码改为:
@Test
public void testDelete() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = (User) session.get(User.class, 2); // 持久化状态
session.delete(user);
session.flush();
System.out.println("+++++++++");
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
再次测试testDelete()方法,会发现Eclipse控制台打印:
Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_ from user user0_ where user0_.id=?
Hibernate: delete from user where id=?
+++++++++
上面例子是使用delete()方法删除一个持久化对象,现在我们来使用delete()方法删除一个游离对象,须修改testDelete()方法的代码为:
@Test
public void testDelete() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
// 模拟一个游离状态的对象并删除
User user = new User();
user.setId(3);
session.delete(user);
session.flush();
System.out.println("+++++++++");
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
再次测试testDelete()方法,会发现Eclipse控制台打印:
Hibernate: delete from user where id=?
+++++++++
注意:我们在删除的时候,如果删除的对象不存在就会抛异常。如将testDelete()方法的代码改为:
@Test
public void testDelete() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
// 模拟一个游离状态的对象并删除
User user = new User();
user.setId(300);
session.delete(user);
session.flush();
System.out.println("+++++++++");
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
再次测试testDelete()方法,会发现抛异常:org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1。
get()
根据给定的OID从数据库中加载一个持久化对象。
现在我们来试验get()方法,编写如下的testGet()方法:
@Test
public void testGet() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = (User) session.get(User.class, 5); // 持久化状态
System.out.println(user.getName());
System.out.println("+++++++++++");
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
测试以上方法,Eclipse控制台打印:
Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_ from user user0_ where user0_.id=?
test_h
+++++++++++
这说明一执行查询,会马上执行sql语句,因为有可能马上就要用到,其他的操作(删除或者更新)都在flush()时执行sql语句。并且如果对象数据不存在,就返回null。
load()
load()和get()非常相似,也能根据给定的OID从数据库中加载一个持久化对象,但是区别真是天差地别啊!
现在我们来试验load()方法,编写如下的testLoad()方法:
@Test
public void testLoad() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = (User) session.load(User.class, 5); // 持久化状态
System.out.println("+++++++++++++");
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
测试以上方法,发现Eclipse控制台没有打印任何sql语句。
但若将testLoad()方法的代码改为:
@Test
public void testLoad() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = (User) session.load(User.class, 5); // 持久化状态
System.out.println("+++++++++++++");
System.out.println(user.getName());
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
再次测试以上方法,发现Eclipse控制台会打印sql查询语句:
+++++++++++++
Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_ from user user0_ where user0_.id=?
test_h
如果我要是将testLoad()方法的代码改为:
@Test
public void testLoad() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = (User) session.load(User.class, 5); // 持久化状态
System.out.println("+++++++++++++");
System.out.println(user.getName());
System.out.println(user.getName());
System.out.println(user.getName());
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
测试以上方法,Eclipse控制台打印:
+++++++++++++
Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_ from user user0_ where user0_.id=?
test_h
test_h
test_h
当getName()很多次时,并不会每次都去数据库里查找,而是查找一次就可以了,将查找到的对象放在Session中。
若将testLoad()方法的代码改为:
@Test
public void testLoad() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = (User) session.load(User.class, 5); // 持久化状态
System.out.println("+++++++++++++");
System.out.println(user.getId());
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
测试以上方法,Eclipse控制台打印:
+++++++++++++
5
这说明一执行查询,不会马上执行sql语句,而是在第一次使用非id或class属性时执行sql语句。
如若将testLoad()方法的代码改为:
@Test
public void testLoad() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = (User) session.load(User.class, 500); // 持久化状态
System.out.println("+++++++++++++");
System.out.println(user.getId());
System.out.println(user.getName());
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
此时,测试以上方法,会报异常:org.hibernate.ObjectNotFoundException。
这说明如果对象数据不存在,就要抛异常——org.hibernate.ObjectNotFoundException。因为获取的时候并没有真正的查询,但还是返回一个对象,返回的是一个代理对象,你这个时候拿这个对象就用了,用了半天,结果发现一执行不存在这个对象,所以就要抛异常。如果你要有这个对象,就得有一个前提,假定它一定是存在的,如果你不能断定,就要调用get()方法先判断该对象是否为空,再做操作。
若将testLoad()方法的代码改为:
@Test
public void testLoad() {
Session session = sessionFactory.openSession();
session.beginTransaction();
// -------------------------------------------
User user = (User) session.load(User.class, 5); // 持久化状态
System.out.println(user.getClass()); // load()返回的是一个代理对象,通过子类的方式进行增强
System.out.println("+++++++++++++");
System.out.println(user.getId());
System.out.println(user.getName());
// -------------------------------------------
session.getTransaction().commit();
session.close();
}
此时,测试以上方法,Eclipse控制台打印:
class cn.itcast.h_session_method.User_$$_jvst57_0
+++++++++++++
5
Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_ from user user0_ where user0_.id=?
test_h
这说明load()后返回的是一个代理对象,要求类不能是final的,否则不能生成子类代理,就不能使用懒加载功能了。让懒加载失效的两种方式:
- 把实体类写成final的。
- 在hbm.xml中写
<class ... lazy="false">
,lazy属性默认为true,默认可以懒加载。
get()和load()的区别
方法 | 加载方式 | 返回值 | 如果数据不存在 |
---|---|---|---|
get() | 立即加载 | 真实对象或null | 返回null |
load() | 延迟加载 | 代理对象 | 抛异常 |
(转) Hibernate框架基础——操纵持久化对象的方法(Session中)的更多相关文章
- hibernate框架学习之持久化对象OID
持久化对象唯一标识——OID 1)数据库中使用主键可以区分两个对象是否相同2)Java语言中使用对象的内存地址区分对象是否相同3)Hibernate中使用OID区分对象是否相同Hibernate认为每 ...
- (转)Hibernate框架基础——一对多关联关系映射
http://blog.csdn.net/yerenyuan_pku/article/details/52746413 上一篇文章Hibernate框架基础——映射集合属性详细讲解的是值类型的集合(即 ...
- Hibernate框架基础
Hibernate框架基础 Hibernate框架 ORM概念 O, Object 对象 R, Realtion 关系 (关系型数据库: MySQL, Oracle…) M,Mapping 映射 OR ...
- Hibernate——(5)持久化对象和一级缓存机制
一.对象的三种状态 1.暂时态:当对象刚创建,和Session没有发生任何关系时,当程序运行完就即刻消失,被称为暂时态. 2.持久态:当执行如下代码时,对象变为持久态 Emp e = new Emp( ...
- (转)Hibernate框架基础——Java对象持久化概述
http://blog.csdn.net/yerenyuan_pku/article/details/52732990 Java对象持久化概述 应用程序的分层体系结构 基于B/S的典型三层架构 说明 ...
- (转)Hibernate框架基础——在Hibernate中java对象的状态
http://blog.csdn.net/yerenyuan_pku/article/details/52760627 在Hibernate中java对象的状态 Hibernate把对象分为4种状态: ...
- hibernate系列笔记(3)---持久化对象
持久化对象 再讲持久化对象之前,我们先来理解有关session中get方法与 load方法区别: 简单总结: (1)如果你使用load方法,hibernate认为该id对应的对象(数据库记录)在数据库 ...
- hibernate框架基础描述
在hibernate中,他通过配置文件(hibernate,cfg.xml)和映射文件(...hbm.xml)把对象或PO(持久化对象)映射到数据库中表,然后通过操作持久化对象,对数据库进行CRUD. ...
- (转)Hibernate框架基础——映射普通属性
http://blog.csdn.net/yerenyuan_pku/article/details/52739871 持久化对象与OID 对持久化对象的要求 提供一个无参的构造器.使Hibernat ...
随机推荐
- 在docker上安装运行mysql实例
ps:实验环境是:CentOS Linux release 7.3 64位1.获取mysql镜像从docker hub的仓库中拉取mysql镜像docker pull mysql查看镜像docker ...
- - > 贪心基础入门讲解三——活动安排问题二
有若干个活动,第i个开始时间和结束时间是[Si,fi),活动之间不能交叠,要把活动都安排完,至少需要几个教室? 分析:能否按照之一问题的解法,每个教室安排尽可能多的活动,即按结束时间排序,再贪心选 ...
- ORA-15024: discovered duplicately numbered ASM disk 0
在尝试删除一个diskgroup的时候遇到这个错误. ORA-15024: discovered duplicately numbered ASM disk 0 这说明oracle认为有两个disk ...
- 表格属就用treegrid
http://maxazan.github.io/jquery-treegrid/ 如果想ajax后台动态添加表格数据然后再形成treegrid,那么可以通过后台给一个对应行索引的数组, 进行动态改变 ...
- Raphael.js image 在ie8以下的兼容性问题
Raphael.js 在ie7,ie8浏览器内绘制图形採用的vml,在绘制image的时候会解析成 <?xml:namespace prefix = "rvml" ns = ...
- 专注UI——是alert()打败了你!
在上家公司.常常在页面上写aler()提示代码.没有认为有什么,好寻常.认为提示就本来应该是这种,可是,当我到了这家公司.在測试的时候,由于測试人员看到了一个aler弹出框.结果我的页面被退回重写,后 ...
- 从头认识Spring-1.9 内部类注入Bean
这一章节我们来讨论一下内部类注入Bean. 1.domain 蛋糕类:(跟前一章节的一样) package com.raylee.my_new_spring.my_new_spring.ch01.to ...
- 【Unity】用Shader编程实现3D红心
有些形状,即使没有3D美术设计师提供模型,也能够用代码生成. 对于想保持原创性不想借用他人模型的独立开发人员来说,这无非是一个非常重要的途径. 今天献给大家的是用Shader编程实现的一颗红心,寄托下 ...
- vim g 和 % 区别
vim中的g(global)和%的区别: g:全局的 s/pattern/replacement/ : 替换行中出现的每一个pattern g/pattern/s/pattern/replaceme ...
- POJ3090 巧用欧拉函数 phi(x)
POJ3090 给定一个坐标系范围 求不同的整数方向个数 分析: 除了三个特殊方向(y轴方向 x轴方向 (1,1)方向)其他方向的最小向量表示(x,y)必然互质 所以对欧拉函数前N项求和 乘2(关于( ...