第 1 章 Hibernate 入门
1 Hibernate 的 优势
简化了对数据库的操作,是建立在JDBC的基础上的。是对JDBC有丰富开发经验的人根据实际使用JDBC的经验,
对JDBC操作进行了封装,Hibernate要求所有使用它的开发者,必须将数据库的链接信息房在一个配置文件中,
这样不仅有利于项目的实施,而且降低了项目的风险,当数据库连接信息发生了变化,用户只需要修改配置文件信息就可以了。不用重新修改和编译源代码。
2.Hibernate 的部署 (使用MyEclipse)
第一步: 右击项目 -- 选中MyEclipse -- Add Hibernate .....
第二步: 上面选3.3 , 中间三个全打钩 , 下面选copy到lib目录下
第三步: 默认设置
第四步: 数据库连接, 可以先不设置。 把钩取消了。
第五步: 创建Hibernate工厂类。 输入包名。你要放入哪个包下面 。 一般为util
第六步: 设置数据库连接与自动生成数据库表对应得实体类和配置文件(文件名.hbm.xml)。(生成的配置
文件数据类型比较坑。看情况改动)
设置连接之后要把jar包复制到lib目录去。
3.配置文件大揭秘 --如下配置文件
<hibernate-mapping>
<class name="com.houserent.entity.Users" table="USERS" schema="HOUSERENT">
<id name="id">
<column name="ID"/>
<generator class="sequence">
<param name="sequence">SEQ_ID</param>
</generator>
</id>
<property name="name" type="java.lang.String">
<column name="NAME" length="50" />
</property>
<property name="password" type="java.lang.String">
<column name="PASSWORD" length="50" />
</property>
<property name="username" type="java.lang.String">
<column name="USERNAME" length="50" />
</property>
</class>
</hibernate-mapping>
class 节点 : 定义一个实体类的映射信息
常用属性:name 表示对象实体类的全限定名 table表示对应得数据库表名
id 节点: 该属性到数据库表的主键字段的映射
常用属性:name 表示实体类属性的名字。 type 表示实体类属性的类型 column 表示数据库表字段的
名字,也可以在column节点中指定
generator节点:对于主键的自动增长序列的生成策略
常用属性和子元素:class 指定主键的具体生成策略 param 用来传递参数
策略:class的指定值:
increment 对long . short int 以自动增长的方式生成主键值。 递增 1
identity 对Sqlserver DB2 MySql 支持标识列的数据库主键自动增长,但数据库中必须设置为标
识列
sequence 对Oracle DB2 等支持序列的数据库生成自动增长主键。 通过param传递序列名
native 自动生成 不需要管
assigned 暂未发现用处
property节点: 定义实体类中属性和数据库表的字段的对应关系
常用属性:name 表示实体类属性的名字
type 表示实体类属性的类型
column 表示数据库表字段的名字,也可以在column节点中指定
column 节点: 用于指定父元素代表的实体类属性所对应的数据库表中的字段
常用属性:name: 表示数据库字段的名字
length: 表示数据库字段的长度
not-null:true表示不能为空
4.Hibernate 操作数据库 (简化方式)
//增删改
public void [对应操作的方法名](Object obj) {
Session session = null;
Transaction tx = null;
try {
//从工厂类中获取session
session = HibernateSessionFactory.getSession();
//开启事务
tx = session.beginTransaction();
//把对象保存进数据库。
//session.save(obj);
//根据这个对象。来删除这条数据。
//session.delete(obj);
//修改对应的这条数据
//session.update(obj);
//提交事务
tx.commit();
} catch (Exception e) {
e.printStackTrace();
if (tx != null)
//如果有错误。就回滚
tx.rollback();
} finally {
//关闭session
session.close();
}
}
//查询 参数1为id值。参数2为类的类型如:Student.class 。
public Object get(Serializable key,Class clazz) {
Object result = null;
Session session = null;
Transaction tx = null;
try {
session = HibernateSessionFactory.getSession();
tx = session.beginTransaction();
result = session.get(clazz,key);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
if (tx != null)
tx.rollback();
} finally {
session.close();
}
return result;
}
5. Hibernate 中实体对象的三种状态
瞬时状态:
在使用持久化操作前, 实例化User对象。此时User对象并未与数据库中的数据有任何关系,这就是
瞬时状态,就是在内存中瞬时存在,与数据库记录无关
持久状态:
当使用Session的get或者load方法加载数据库中的一条记录的时候,返回的User对象时与数据库中一
条数据关联的。此时的User对象为持久状态
游离状态:
处于持久状态的对象,其对于的Session实例关闭后。User对象的各个属性的值与数据库中一条数据
的值是对应的。但是此时User对象并未受到Session实例的管理,所以此时User对象处于游离状态。
第 2 章 Hibernate 映射
记住首先要把所有实体类的配置文件信息添加到 hibernate.cfg.xml的Mappings里面去
1.在 hbm.xml的
多对一配置:
如: 在街道实体类(street)中有这样一个区对象 。。
private District districtId;
在配置文件中。
<many-to-one class="com.houserent.entity.District" name="districtId">
<column name="district_id"/>
</many-to-one>
配置文件值对应为:
<many-to-one class="一方全限定名" name="多方对应的对象名">
<column name="多方数据库表对应的字段名"/>
</many-to-one>
当你查询出一个街道的时候。 districtId的值, 就会自动有了。 就是街道对应的区对象!
2.一对多配置:
如:在区实体类(District)中有这样一个街道集合
private Set<Street> streets = new HashSet<Street>();
在配置文件中。
<set cascade="all" name="streets" table="street" inverse="true">
<key column="district_id"/>
<one-to-many class="com.houserent.entity.Street"/>
</set>
配置文件对应为
<set cascade="级联操作值" name="一方对应的对象名" table="多方数据库对应的表名"
inverse="true">
<key column="关联的外键名"/>
<one-to-many class="多方的全限定名"/>
</set>
当你查询出一个区的时候。streets集合中,就会自动塞满所有属于这个区的街道
小提示:单向一对多和多对一可以分别配置实用,如果同时配置了两者。那就是成了双向一对多关联。
3.cascade属性 (级联操作)
值:all : 对所有操作进行级联操作
save-update:保存和修改级联操作
delete:删除操作级联
none : 不进行级联。
4.inverse 属性
反转的意思。指定关联关系中的方向。inverse = "false"的为主动方。 主动方负责维护关联关系
一对多关联中。 将one方设置 inverse = "true" 有助于性能的改善
5.多对多配置。
假如数据库有表:Student ,字段有: stu_id , stu_name 还有表:teacher 字段有:tea_id ,
tea_name
这是典型多对多。老师和学生。 自然的就会生成第三张表 :r_stu_tea 字段有:r_stu_id , r_tea_id
Student实例类中有:private Set<Teacher> teachers = new HashSet<Teacher>();
Teacher实体类中有:private Set<Student> students = new HashSet<Student>();
在配置文件中。
Student 方
<class name= "Student" table = "Student">
<set name="teachers" table="r_stu_tea" inverse="true">
<key column="r_stu_id"/>
<many-to-many class="entity.Teacher" column="r_tea_id"/>
</set>
</class>
Teacher 方
<class name= "Teacher" table = "Teacher">
<set name="students" table="r_stu_tea">
<key column="r_tea_id"/>
<many-to-many class="entity.Student" column = "r_stu_id"/>
</set>
</class>
第 3 章 HQL实用技术
1.使用HQL
第一步:得到Session
第二步:编写HQL语句
第三步:创建Query对象
第四步:执行查询,得到结果
以下代码所示:
//hql语句
String hql = "from House";
Session session = null;
try {
//得到session
session = HibernateSessionFactory.getSession();
//创建Query对象
Query query = session.createQuery(hql);
//执行查询,得到结果.
List<House> list = query.list();
for(House h : list){
System.out.println(h.getTitle());
System.out.println(h.getDescription());
}
} catch (Exception e) {
e.printStackTrace();
}finally{
session.close();
}
2.实体查询
hql是种面向对象的查询语言,所以要注意的是。在配置好配置文件之后。
hql语句 "from House" 的House是指实体类名, 而不是数据库表名,严格区分大小写。
如果House存在子类,那么子类的数据也会全部查出来。即时子类对应不同表。
3.属性查询
String hql = "select u.name from House u";
只查询单个值。
4.参数绑定
4.1 "?"占位符
与JDBC的?占位符类似。
给?占位符填值有些不一样。 使用Query对象的 setXxx方法填值。 注意下标从0开始,
而JDBC是从1开始的
代码案例:
String hql = "from Users where name = ?";
对应。
query.setString(0, userName);
4.2 命名参数
通过 :名字 的方式定义占位符 然后用query对象的setXxx方法赋值
代码案例:
String hql = "from Users where name = :name";
对应。
query.setString("name", userName);
4.3 封装参数
查询条件很多的情况下。可以把条件封装成一个Bean,然后通过Query对象的setProperties方法实现参
数设定
代码案例:
Bean类 有很多查询条件 。 全部封装在这里
类名比如为:QueryBean
private Integer typeId;
private String title;
private Integer min_price;
private Integer max_price;
private Integer min_floorage;
private Integer max_floorage;
private Integer streetId;
--省略
//很多查询条件。 语句很长
String hql = "from House t where type_id = :typeId and street_id = :streetId and (price
between :min_price and :max_price) and (floorage between :min_floorage and :max_floorage)";
//放入一下查询条件bean类的实例。就可以了。如果一个一个设置。那会很长。你懂的。
query.setProperties(new QueryBean(参数省略));
5.聚合函数
//其他的聚合函数如 max , min , avg , sum 和sql一致
String hql="select count(u) from Users u";
6.排序
//与sql 一致
String hql="from Users u order by u.id";
7.分组
//查询租房面积大于1000的街道的数量
String hql = "select sum(house.floorage) from House house guoup by house.street_id having
sum(house.floorage)>1000"
8.分页
hql实现分页非常简单。通过设置query对象的setFirstResult()方法和setMaxResult()方法就可以实现
了。
代码案例:
String hql = "from House";
Session session = null;
try {
session = HibernateSessionFactory.getSession();
Query query = session.createQuery(hql);
//page为当前页,pageSize为每页显示的数量.setFirstResult方法参数1意思为,从
第几行开始读取
query.setFirstResult((page-1)*pageSize);
//setMaxResults方法参数1意思为,每次读取数据的行数
query.setMaxResults(pageSize);
List<House> list = query.list();
以下省略
如pageSize 为5 page为1 那么就是从第 (1-1)*5行 开始,取5条数据 取出 01234
如pageSize 为5 page为2 那么就是从第 (2-1)*5行 开始,取5条数据 取出 56789
9.子查询
与sql 一样。 如下代码案例:
查询价格大于 平均价格的房屋
select * from House as h1 where h1.price>(select avg(h2.price) from House h2)
第 4 章 HQL进阶
1.HQL优化
1.1 避免or操作
很多情况下,如果where子句中包含or操作,那么执行将不使用索引,某些环境下可以用in替换
1.2 避免使用not
如果where子句条件包含not关键字,那么执行时该字段的索引无效,
1.3 避免like的特殊形式
如果like以 % 或者 _ 开始,那么该字段索引不起作用
1.4 避免having子句
尽可能在where指定条件而不是在having中指定
1.5 避免使用distinct
指定 distinct 会导致在结果中删除重复的行,这对处理时间会造成一定影响当允许冗余的时候,应该
避免使用它
2.数据加载方式
2.1 即时加载
当实体加载完成后,立即加载其关联数据, 比如 District 配置文件中对应的字段设置 lazy="false"
那么就是即时加载,当加载Street的时候,立刻就加载了它对应的District对象,
即时加载的基本原理,就是当数据加载时,Hibernate会自动加载其关联的数据。,
2.2 延迟加载
延迟加载机制是避免一些无谓的性能开销提出来的。延迟加载就是当你真正需要数据的时候,才执行
数据加载操作。
2.2.1 集合延迟加载
比如District对象有个Street的set集合,将set元素设置lazy = "true" ,那么。当获取District
对象的时候,集合不会立即加载,而当你去获取这个集合的时候,才会发送语句。获取数据,性能
大幅提高。
2.2.2 实体对象延迟加载
给class设置 lazy = "true" 就是当获取一个对象出来的时候,并不会发生语句查询这个对象的数
据。
而当你使用的时候。就会去查询数据了。
3. list() 和 iterate()
3.1 list()和iterate()的区别
1.使用list()方法获取查询结果,每次发出一条查询语句,获取全部的数据
2.使用iterate()方法获取查询结果。先发送一条语句获取所有满足条件的id,
然后根据id查询记录,也就是要执行 N+1条sql语句,(N为符合条件的记录数)
3.list()方法将不会在缓存中读取数据,它总是一次性的从数据库中直接查询
出所有符合条件的数据,同时将数据写入缓存
4.使用iterate()方法获取查询结果。先发送一条语句获取所有满足条件的id,
然后根据id在缓存中查询符合条件的数据,若无符合条件的数据,再到数据库查询
4. HQL联接查询
只有5种查询方式:内连接,迫切内连接,左外连接,迫切左外连接,右外连接
left right fetch
4.1 内联接:inner join
代码案例: from District d inner join fetch d.streets s
sql中使用on 联接对应的关系,在Hibernate中已经由映射文件制定,因此不需要了
fetch 加了这个关键字就是迫切连接了。当查询出District的数据的时候,自动会
把查出来对应的Street的数据塞入到District的集合中,
如果不使用fetch关键字,那么就不会喔。
5. 命名查询
就是把查询语句 放到 配置文件中, 与class节点同级, 以<![CDATA[HQL]]>的方式
保存语句, 代码如下所示:
User类的配置文件中 写入
<query name = "findUsers">
<![CDATA[from User]]>
</query>
在代码中 。 使用 Query query = session.getNamedQuery("findUsers");
来获取该查询语句。
6. 本地sql查询
hql虽然强大, 但不能覆盖所有的查询特性。有的时候还是要用到sql语句。
如下sql 语句:
select {u.*} from users u
其中,u是别名,{}表示引用实体的属性,在实例中,使用{u.*} 标记所有属性。
执行本地sql查询使用 SQLQuery接口。 还需要配置addEntity(别名,实体类)方法一起使用。代码如下:
session.createSQLQuery(sql).addEntity("u",User.class); u是语句中表的别名
可以查询多个 {u.*}{d.*} 那么 addEntity方法就要连续调用了
如果配合命名查询,那么在配置文件中 。
<sql-query name = "findUsers">
<![CDATA[select {u.*} from user]]>
<return alias = "u" class="entity.User">
</sql-query>
return 节点,表示配置对应的实体类。alias表示别名。class是全限定名
第 5 章 Criteria查询
Criteria查询使用面向对象的方式封装查询条件,即时对sql语句不了解,也可以进行查询。
1.Criteria查询使用方式
1.1代码案例:
Criteria criteria = session.createCriteria(User.class); //传入实体类
List result = criteria.list(); //直接就可以获得User对应的数据表的所有数据
1.2 带条件查询
Criteria criteria = session.createCriteria(User.class); //传入实体类
criteria.add(Restrictions.eq("name","admin")); //查询name为admin的数据, 添加Restrictions,
参数1为判断哪个字段,参数2为判断的值
List result = criteria.list();
2.Restrictions常用的查询方法
Restrictions.eq() 对应sql的等于 =
Restrictions.allEq() 使用Map,使用key/value进行多个对等值得对比
Restrictions.gt() 对应sql的 >
Restrictions.ge() 对应sql的 >=
Restrictions.lt() 对应sql的<
Restrictions.le() 对应sql的<=
Restrictions.between() 对应sql的 between
Restrictions.like() 对应sql的like
Restrictions.in() 对应sql的 in
Restrictions.and() 对应sql的 and
Restrictions.or() 对应sql的or
Restrictions.not() 对应sql的 not
3.使用Example
如果属性条件很多,以上方法就不方便了,如果已经有一个对象,那就可以根据这个对象作为查询的依据
,
查询出属性与之类似的对象,如现有租金为1500元,面积为75的房屋对象,查询出与之类似的数据。
支持等于喔。很多方面不支持
代码案例:
House h =new House();
h.setPrice(1500d);
h.setFloorage(75);
//省略获得session代码。
Criteria criteria = session.createCriteria(User.class); //传入实体类
criteria.add(Example.create(h));
List result = criteria.list(); //直接就可以获得User对应的数据表的所有数据
4.Criteria查询排序
Criteria对象.addOrder(Order.desc("Price")); //根据价格降序
Criteria对象.addOrder(Order.asc("Price")); //根据价格升序
5.Criteria查询限定返回数据行数和分页
Criteria对象的setMaxResults() 方法可以限定查询返回数据的行数,
配合Criteria对象的setFirstResult()设定查询返回结果的第一行数据的位置,
就可以实现分页了
代码案例:
Criteria对象.setMaxResults((page-1)*5); //page就是当前页。 是1的话, 那就是从第0条开始 ,
取到第4条数据
Criteria对象.setFirstResult(5); 是2个话, 就是从第5条数据开始, 取到第9条数据
Projections
第 6 章 Filter 过滤器
1. 过滤器的执行过程。
配置了Filter过滤器之后。在运行某个Servlet的时候就会先运行Filter。然后再去运行Servlet
,先执行init() , 然后执行 Filter()
2. 配置Filter 的配置信息
在web.xml里面配置Filter
<filter>
<filter-name>TestFilter</filter-name> //filter的名称
<filter-class>filter.TestFilter</filter-class> //对应的filter类的全限定名
<init-param> //初始化参数
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping> //filter映射
<filter-name>TestFilter</filter-name> //对应的filter的名称
<url-pattern>/FindServlet</url-pattern> //这个filter所作用的范围。这里的意思就是
这个TestFilter作用于FindServlet
</filter-mapping> 如果用 /* 的话。 就是作用全部Servlet。
3. 编写Filter类
package filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class TestFilter implements Filter{ //需要实现Filter接口。
private String encoding = null; //字符编码
public void destroy() { //销毁的时候调用此方法。
System.out.println("销毁");
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException { //处理
请求
System.out.println("执行编码");
request.setCharacterEncoding(encoding); //设置编码格式、
chain.doFilter(request, response); //把请求发送到下一个Filter或者
Servlet
}
public void init(FilterConfig config) throws ServletException {
System.out.println("执行初始化");
encoding = config.getInitParameter("encoding"); //获取初始化参数值。
}
}
第 8 章 PL/SQL
1.PL/SQL
答:PL/SQL是一种复杂的程序设计语言,它将第四代语言的强大功能和灵活性与第三代语言
的过程结构的优势有效的结合在一起,除了支持所有的对数据库操作的sql语句外,
同样还支持动态sql,能够动态执行sql语句定义,数据控制和会话控制语句。
2.PL/SQL语句块
declare 变量声明部分
begin 语句块开始部分
end 结束部分
3.变量和常量
declare 变量名 [constant] 变量类型 [not null] [:=值]
其中 declare 表示声明;
constant表示是否是常量,可选。
not null 表示变量不能为空,可选
最后的表示赋初始值, 可以先不赋值。
代码案例:
declare //变量声明块开始
v_a int := 10;
v_b int := 20;
命名规则为:变量名长度不超30字符,变量名不能有空格,变量名首字符必须是英文字符,
其后可以是字母,数字或者字符$,#,_
4.条件结构
4.1 if then 结构
代码案例:
if (10 > 2) then
dbms_output.put_line('10大于2'); //输出语句
end if; //记得用分号结束
4.2 if then else 结构
代码案例:
if (10 > 2) then
dbms_output.put_line('10大于2'); //输出语句
else
dbms_output.put_line('2大于10'); //输出语句
end if; //记得用分号结束
4.3 if then elsif 结构 相当于 java多重if
if (v_age < 10) then
dbms_output.put_line('年龄<10!!!');
elsif (v_age >= 10 and v_age < 20) then
dbms_output.put_line('v_age >= 10 and v_age < 20');
else
dbms_output.put_line('v_age >= 20 !!!');
end if;
注意:是elsif 不是elseif 这里少了个e
4.4 case 语句
代码案例:
--相当于一个switch
case v_sex //判断条件。 如果v_sex 值为0 , 那么输出 男 否则输出女
when 0 then
dbms_output.put_line('男');
else
dbms_output.put_line('女');
end case;
--相当于一个多重if
case //可以先不设定
when (v_age < 10) then
dbms_output.put_line('年龄<10!!!');
when (v_age >= 10 and v_age < 20) then
dbms_output.put_line('v_age >= 10 and v_age < 20');
else
dbms_output.put_line('v_age >= 20 !!!');
end case;
5.循环结构
5.1 LOOP END LOOP 结构。
LOOP
v_count := v_count + 1;
dbms_output.put_line(v_count);
IF v_count >= 10 THEN
EXIT; //使用EXIT退出。 不退出会死循环
END IF; //注意分号
END LOOP; //注意分号
5.2 while LOOP END LOOP 结构
//while循环, 首先判断循环条件再进入。进入后条件不满足的时候退出。
WHILE (v_count <= 10) LOOP
v_count := v_count + 1;
dbms_output.put_line(v_count);
END LOOP;
5.3 for LOOP END LOOP
--for循环,可选的reverse来反转循环变量,循环变量可以不声明直接使用
FOR i IN 1 .. 10 LOOP // i为循环变量, 1 .. 10 就是从1到10 循环10次
dbms_output.put_line(i);
END LOOP;
6.动态SQL
可以把sql语句作为字符串进行运行
6.1 执行ddl
begin
execute immediate 'create table ..省略';
end
6.2 绑定变量
declare
plsql varchar2(200);
t_name varchar2(20);
t_id integer:='1002';
begin
plsql :='insert into temp_table values(:1,:2)'; //:1 ,1为占位符名,
execute immdiate plsql using t_id,t_name; //传递两个参数填充进去
end;
6.3 获取回调值 returning into
//演示了获取动态sql执行后的回调值
declare
v_id number;
v_name varchar2(20);
v_age number;
v_str varchar2(200);
begin
--:xx表示占位符,returning子句后的占位符相当于输出占位符,需要用变量来接收输出的内容
v_str := 'update temp_table set name=''孙武空''
where id=:1 returning id,name into :t2,:t3';
execute immediate v_str
using 1
returning into v_id, v_name;
commit;
dbms_output.put_line('编号:' || v_id || ',姓名:' || v_name);
end;
7.异常处理
代码案例:
declare
v_age number := 20;
myException exception; //声明异常myException
begin
if(v_age=50) then
raise myException; // raise 触发异常
elsif v_age=40 then
dbms_output.put_line('40男人一枝花');
else
dbms_output.put_line('顶呱呱');
end if;
dbms_output.put_line('年龄合适');
exception //处理异常
when myException then //处理异常
dbms_output.put_line('年龄太大了');
end;
8.游标
8.1游标的属性
%FOUND 描述:用于检测游标是否成功,当查出一条数据的时候返还True
%ISOPEN 描述:用于判断游标是否被打开。如果视图打开一个已经打开或关闭的游标,将出现错误
%NOTFOUND 描述:与%FOUND相反
%ROWCOUNT 描述:循环执行游标读取数据的时候,返还检索出的记录行数的总数
总结:%看起来怪怪的 ,可以想象成. 如:游标对象.rowcount, 游标对象%rowcount ,别扭只是习惯问题
8.2游标的使用
1.声明游标
cursor 游标名 [参数列表 ,可选的][返还值 返还值类型 可选的] is 查询语句
代码案例如下:
2. 显示游标示例
declare
v_name district.name%type;
v_districttype district%rowtype; --定义一个对应表的行类型
cursor d_cursor is select * from district where id=1000; //1.声明游标
begin
--2.打开游标
open d_cursor;
--3.抓取游标内容 给 v_districttype变量;
fetch d_cursor into v_districttype;
dbms_output.put_line(v_districttype.name||v_districttype.id);
//4.关闭游标
close d_cursor;
end;
3. 游标循环提取
只写for循环的读取方式。其他的循环的读取方式 。太少用。不建议用.不好用
--循环游标--for
declare
cursor d_cursor is select * from district; //声明游标
begin
--for循环遍历游标,隐式打开和关闭游标
for t_district in d_cursor
loop
dbms_output.put_line(t_district.name||t_district.id);
end loop;
end;
第 9 章 Oracle数据库对象
1.过程
1.1简介:过程是为了只学一定的任务,实现特定的功能,是将sql或者pl/sql代码集中在一起的代码语句
集合,
过程包括声明部分,执行部分,异常处理部分,过程一般被设计成求若干个运算结果,完成一系列的数据
处理
语法:create [or replace] procedure 过程名 --中括号[] 里面的表示可有可无
[(参数列表)] as begin 过程体 end --or replace表示如果存在此名称的过程,
则覆盖
1.2代码案例:
create or replace procedure InserCar --创建过程
(v_carId [in|out|in out] varchar2, --参数列表 , 中间如果不写,默认是in输入参数,
v_carType [in|out|in out] varchar2, 也可以是out输出参数和in out
v_carPrice [in|out|in out] number,
v_carNewDate [in|out|in out] date,
v_carExhaust [in|out|in out] number
) as
[declare] --声明变量部分可有可无,声明变量
begin --过程体
insert into store_car values (v_carId, v_carType, v_carPrice, v_carNewDate,
v_carExhaust);
commit;
end;
1.3调用过程: 只用在begin end 里面调用就可以了
declare
v_carId varchar2(20) :='89759';
begin
InserCar(v_carId,'宝马',50,sysdate,5);
end;
1.4删除过程:
drop procedure 过程名
2.函数
2.1简介:与过程类似,函数与过程最大的区别在于,函数最终任务是返回一个表示结果的值,
另外函数的调用是表达式的一部分,而过程的调用本身就是一条pl/sql语句
语法:create [or replace] function 函数名 --中括号[] 里面的表示可有可无
[(参数列表)] return 返回的数据类型 as begin 过程体 end --or replace表示如果存在此名称的过
程,则覆盖
2.2代码案例:
create function addCar(
v_carid varchar2,
v_cartype varchar2,
v_carprice number,
v_carnewdate date,
v_carexhaust number
) return number as -- 必须声明返回的数据类型
--这里如果要声明变量,直接声明就可以了 不需要declare了,这是函数的特点
begin
insert into store_car values (v_carid, v_cartype, v_carprice, v_carnewdate,
v_carexhaust);
commit;
return 1; --必须返回值
end;
2.3调用函数: 用法和系统函数类似。自己体会, 必须max()函数,min()函数等等
declare
co number;
begin
--必须接收或者查询返回值。否则报错
co:=addCar('88888','奔驰',500,sysdate,40);
end;
2.4删除函数:
drop function 函数名;
3.过程和函数的比较
1.标示符不同,函数一般不采用变量形参,
2.函数名运行完直接return函数值。而过程的返回值必须使用变量形参返回。
3.不能给过程名赋值。也不能定义过程类型,但是函数可以有类型,并可以将函数值传递给函数名。
4.函数在定义时一定要定义函数的类型说明,过程不用。
5.函数的调用出现在表达式中。而过程有独立的过程调用语句来完成。
6.过程一般被设计成求若干个运算结果,完成一系列的数据处理,而函数值为了求一个函数
4.Oracle中的包
简介:包分为两部分,包头和包体,包头就是包的规范,类似于接口。而包体类似于实现类。
里面可以有函数和过程,变量等。
4.1 包头的创建
语法:
--注意! 包头和包体要分开执行。否则会出现错误!
create or replace package 包名 as
包规范,可以有函数,过程,变量等等
end 包名;
代码案例:
create or replace package car_package as
function addCar( --定义过程,不需要create了。类似接口,包体必须实现。
v_carid varchar2,
v_cartype varchar2,
v_carprice number,
v_carnewdate date,
v_carexhaust number
) return number;
procedure InserCar --定义函数,不需要create了,类似接口,包体必须实现。
(v_carId in varchar2,
v_carType in varchar2,
v_carPrice in number,
v_carNewDate in date,
v_carExhaust in number
);
end car_package;
4.2 包体的创建
--注意! 包头和包体要分开执行。否则会出现错误!
语法:
create or replace package body 包名 as --多了body
实现包头里的所有东西,
end 包名;
代码案例:
create or replace package body car_package as
function addCar( --上例过程的实现
v_carid varchar2,
v_cartype varchar2,
v_carprice number,
v_carnewdate date,
v_carexhaust number
) return number as -- 必须声明返回类型sss
begin
insert into store_car values (v_carid, v_cartype, v_carprice, v_carnewdate,
v_carexhaust);
commit;
return 1;
end addCar; --结束这个过程
procedure InserCar --上例函数的实现
(v_carId in varchar2,
v_carType in varchar2,
v_carPrice in number,
v_carNewDate in date,
v_carExhaust in number
) is
begin
insert into store_car values (v_carId, v_carType, v_carPrice, v_carNewDate,
v_carExhaust);
commit;yh
end InserCar;
end car_package; --结束这个函数
4.3 包的调用
就根据上例进行调用,直接用 包名. 就可以了
declare
co number;
begin
--必须接收或者查询返回值。否则报错
co:=car_package.addCar('88888','奔驰1',500,sysdate,40);
car_package.InserCar('89759','宝马1',50,sysdate,5);
end;
5.视图
5.1简介:
视图简单来说就是一张虚拟的表,是经过查询操作后形成的一个结果。其输出形式类似一个表。
视图是对一个真实表的引用、 不能对数据进行修改
5.2创建:
create or replace view 视图名 as
查询语句 [with check option] --with..表示进行插入或者修改的数据记录必须满足视图定义的约束
代码案例:
create view view_student as
select stu_name,stu_age from student
5.3查询:
select * from 视图名
5.4删除:
drop view 视图名
5.5权限问题:
创建视图需要创建视图的权限,必须赋予这个用户权限。
--用dba权限给lesson9用户创建视图的权限
grant create any view to 用户名; --给需要创建视图的用户赋予权限
6.序列
简介:
序列是用来生成一系列唯一数据的数据库对象,可以实现自增的效果。
创建:
create sequence 序列名
start with 1 -- 设置种子为1
increnment by 1 --设置每次递增1,负数为递减
[maxvalue 数字] --设置序列最大值
[minvalue 数字] --设置最小值
修改:
alter sequence 序列名 --不能修改种子数了.
increnment by 1 --设置每次递增1,负数为递减
[maxvalue 数字] --设置序列最大值
[minvalue 数字] --设置最小值
删除:
drop sequence 序列名
使用:
序列名.nextval 返回下个一值。
序列名.currval 返回当前值
7.数据库链
简介:
Database link 能够实现从一个数据库实例访问到另外一个数据库实例(可以是本地或者远程)
创建:
create database link link_sales --数据库链的名称为link_sales
connect to sales identified by sales --对方数据库的登录名和密码。
using '(description =
(address_list = (address = (protocol = tcp)(host = 127.0.0.1)(port = 1521)) --host的值为
ip地址。
)
(connect_data = (service_name = sales)) --service_name的值为目标的数据库实例名
)';
访问:
select * from seles@link_sales --查询seles表的时候,后面跟上数据库链的名字
第 10章 提高数据库性能
1.索引: 之前有很多索引的资料了。不多做介绍了
创建:create [unique] index 索引名 on 表名(列名)
2.表分区:
简介:增强数据库的可用性,分区了,一部分分区出了问题,。只用修复这一部分。
减少维护工作量,均衡IO,提高查询效率,分区对用户保持透明,就是把表的数据
放在几个磁盘的几个表空间中。
2.1 范围分区(Range)
语法:
partition by range(stu_result)( --范围分区操作stu_result为要分区的字段
partition 分区名 values less than(范围) tablespace 表空间名
)
代码案例:
--创建分区表
create table score --创建表,注意分区要和创建表一起运行。
(
stu_no number primary key,
stu_name varchar2(20) not null,
subject varchar2(20) not null,
stu_result number not null
)partition by range(stu_result)( --范围分区操作,根据学生成绩分区
partition d_p1 values less than(60) tablespace dp1, --60以下的分到dp1这个区
partition d_p2 values less than(80) tablespace dp2, --60-80的分到dp2这个区
partition d_p3 values less than(maxvalue) tablespace dp3 --80以上分到dp1这个区,
maxvalue表示到最大值
);
2.2 列表分区(List)
与范围分区相比,列表分区是枚举的,一般适合低基数列
语法:
partition by list(列名)(
partition 分区名 values (值) tablespace 分区名
)
代码案例:
create table student(
stu_name varchar2(20),
stu_sex varchar2(4)
)partition by list(stu_sex)(
partition man values ('男') tablespace dp1, --把所有男同胞放到dp1,女同伴放到dp2
partition man values ('女') tablespace dp2
)
2.3 散列分区(hash)
是在列取值很难确定的情况下使用的一种分区方式。平均分配下来。数据的分配由
Oracle分配。
代码案例:
create table movie1(
m_id number primary key,
playdate date not null,
statu varchar2(10) not null,
m_name varchar(20),
m_state varchar2(20)
)
partition by hash(m_state)( --根据日期散列分区。
partition part_1 tablespace s1, --part_1为分区名 s1为表空间名
partition part_2 tablespace s2,
partition part_3 tablespace s3
)
2.4 索引分区
2.4.1 本地索引分区
代码案例:
create table score
(
stu_no number primary key,
stu_name varchar2(20) not null,
subject varchar2(20) not null,
stu_result number not null
)partition by range(stu_result)( --范围分区操作
partition d_p1 values less than(60) tablespace dp1,
partition d_p2 values less than(80) tablespace dp2,
partition d_p3 values less than(maxvalue) tablespace dp3
);
create index result_index on score(stu_result) local( --创建本地索引 score表的stu_result
字段
partition d_p1 tablespace dp1,
partition d_p2 tablespace dp2,
partition d_p3 tablespace dp3
);
2.4.2 全局索引分区
create index g_index on score(stu_result) --在范围分区的stu_result字段的基础上加上了全局
索引
global partition by range(stu_result)( --范围分区操作,根据学生成绩分区
partition d_p1 values less than(60) tablespace dp1, --60以下的分到dp1这个区
partition d_p2 values less than(80) tablespace dp2, --60-80的分到dp2这个区
partition d_p3 values less than(maxvalue) tablespace dp3 --80以上分到dp1这个区,
maxvalue表示到最大值
);
课外扩展:
oracle实现任意数字的阶乘
阶乘指从1乘以2乘以3乘以4一直乘到所要求的数。例如所要求的数是4,
则阶乘式是1×2×3×4,得到的积是24,24就是4的阶乘。 例如所要求的数是6,
则阶乘式是1×2×3×……×6,得到的积是720,720就是6的阶乘。例如所要求的数是n,
则阶乘式是1×2×3×……×n,设得到的积是x,x就是n的阶乘。任何大于1的自然数n阶乘表示方法:
n!=1×2×3×……×n 或 n!=n×(n-1)! 5!=5*4*3*2*1=120。
create or replace function fun_n_jc (i in number)
return number
is
n number:=1;
Begin
for c in 1..i loop -- loop到传递过来的参数值
n:=n*c;
end loop;
return n;
end;
declare
numb number;
begin
numb:= fun_n_jc(3);
dbms_output.put_line(numb);
end;