数据库学习记录:Oracle和MySQL学习
数据库学习记录
Oracle数据库
Oracle数据库是以用户为数据库基本单位,每个用户有基本的表空间,表空间的对象一般有tables,views,sequences,triggers,functions,procedures等。
maven坐标
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc14</artifactId>
<version>10.2.0.4.0</version>
</dependency>
由于Oracle数据库在maven中是收费资源,所以一般都是下载好jar包安装到maven仓库。
驱动:oracle.jdbc.driver.OracleDriver
url:jdbc:oracle:thin:@192.168.74.128:1521:orcl
主要的数据类型
VARCHAR2可变长度的字符串,最大长度4000bytes 可做索引的最大长度749。
DATE日期(日-月-年)DD-MM-YY(HH-MI-SS) 。经过严格测试,无千年虫问题。
LONG超长字符串 最大长度2G, 足够存储大部份著作。
RAW固定长度的二进制数据 最大长度2000 bytes 可存放多媒体图象声音等。
LONG RAW可变长度的二进制数据 最大长度2G 同上。
BLOB二进制数据 最大长度4G。
CLOB字符数据 最大长度4G。
数值型:可用于存储整数、浮点数。number(m,n):m表示有效数字的总位数(最大为38位),n表示小数位数。
创建表
基本的sql语句都一样,和MySQL相比最重要的不同就是,它的主键一般使用自定义的序列,而不是像MySQL一样定义主键自增。
-- Create table
create table PERSON1
(
id NUMBER(10) not null primary key,
name VARCHAR2(20) not null,
age NUMBER(2)
)
这种是创建表的一般写法,但实际在执行过程中,有很多条语句
-- Create table
create table PERSON
(
id NUMBER(10) not null,
name VARCHAR2(20) not null,
age NUMBER(2)
)
tablespace ITHEIMA
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 64K
minextents 1
maxextents unlimited
);
-- Create/Recreate primary, unique and foreign key constraints
alter table PERSON
add primary key (ID)
using index
tablespace ITHEIMA
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 64K
minextents 1
maxextents unlimited
);
除了基本的create之外,其他属性都是通过alter修改增加。
创建用于主键的序列
-- Create sequence
create sequence S_PERSON
minvalue 0
start with 1
increment by 1
nocache;
一般是这种写法,默认的maxvalue是个很大的数。
创建视图
视图我个人理解确实是个好东西,结合Oracle数据库产生的背景,感觉这个功能确实强大。
create or replace view p_view as
select "EMPNO","ENAME","JOB","MGR","HIREDATE","DEPTNO" from emp;
原本这个emp表里有sal和comm字段,但用view可以不显示这两列,这就是view高明之处。注意,修改view的数据,原来表emp的数据也能被修改。
内连接
自连接是内连接的一种,内连接可分为等值连接和自身连接。
自身连接: 就是和自己进行连接查询,给一张表取两个不同的别名,然后附上连接条件。
等值连接:查找两个表中连接字段相等的记录。
自连接
select e1.ename,e1.mgr,e2.ename,e2.empno
from emp e1,emp e2
where e1.mgr=e2.empno
等值连接
select emp.ename,emp.deptno,dept.dname
from emp,dept
where emp.deptno=dept.deptno
外连接
外联接可以是左向外联接、右向外联接或完整外部联接。
在 FROM子句中指定外联接时,可以由下列几组关键字中的一组指定:
1)LEFT JOIN或LEFT OUTER JOIN
左向外联接的结果集包括 LEFT OUTER子句中指定的左表的所有行,而不仅仅是联接列所匹配的行。如果左表的某行在右表中没有匹配行,则在相关联的结果集行中右表的所有选择列表列均为空值。
2)RIGHT JOIN 或 RIGHT OUTER JOIN
右向外联接是左向外联接的反向联接。将返回右表的所有行。如果右表的某行在左表中没有匹配行,则将为左表返回空值。
3)FULL JOIN 或 FULL OUTER JOIN
完整外部联接返回左表和右表中的所有行。当某行在另一个表中没有匹配行时,则另一个表的选择列表列包含空值。如果表之间有匹配行,则整个结果集行包含基表的数据值。
select emp.ename,emp.deptno,dept.dname
from emp,dept
where emp.deptno=dept.deptno(+)
--sql99写法
select emp.ename,emp.deptno,dept.dname
from emp left join dept
on emp.deptno=dept.deptno
子查询
select ename,sal
from emp
where sal > (select sal
from emp
where ename='SCOTT'
)
括号中的查询结果作为判断条件
分组查询
select deptno,avg(sal)
from emp
group by deptno
排序
--从小到大排序
select ename,sal
from emp
order by sal
PL/SQL语言
declare
v_num number := 5;
begin
dbms_output.put_line(v_num);
end;
最简单的语句。在declare下定义变量,begin开始执行语句,end结束。
存储函数
create or replace function f_sal(eno emp.empno%type) return number
is
e_sal number(10);
begin
select sal into e_sal from emp where empno=eno;
return e_sal;
end;
这个函数的作用是输出对应员工号的工资。
存储过程
create or replace procedure p_add100(eno emp.empno%type)
is
begin
update emp set sal=sal+100 where empno = eno;
commit;
end;
这段存储过程就是给某个员工工资加100。
存储过程于存储函数的最大区别就是有没有返回值,这个也能从字面意思理解。
整合mybatis
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jdbc-oracle</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>oracle-mybatis</artifactId>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc14</artifactId>
<version>10.2.0.4.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
主要就是在Mybatis的配置文件发生了变化
<environments default="oracle">
<environment id="oracle">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@192.168.74.128:1521:orcl"/>
<property name="username" value="fantasy"/>
<property name="password" value="fantasy"/>
</dataSource>
</environment>
</environments>
<select id="addPerson" parameterType="person">
insert into person values (s_person.nextval,#{name},#{age})
</select>
这里的id就是要用s_person
这个序列实现自增。
调用过程函数
create or replace function f_getname(eno emp.empno%type) return varchar2
is
name varchar2(10);
begin
select ename into name from emp where empno=eno;
return name;
end;
<select id="getNameById" parameterType="Map" resultType="string" statementType="CALLABLE">
{#{name,mode=OUT,jdbcType=VARCHAR} = call f_getname(#{id,mode=IN,jdbcType=NUMERIC})}
</select>
Map param = new HashMap();
param.put("id", 7788);
System.out.println(personMapper.getNameById(param));
运行没问题,但输出是null,不知道哪里出问题了。
调用存储过程
create or replace procedure p_add100(eno emp.empno%type)
is
begin
update emp set sal=sal+100 where empno = eno;
commit;
end;
<update id="add100" parameterType="Map" statementType="CALLABLE">
{call p_add100(#{id,mode=IN,jdbcType=NUMERIC})}
</update>
Map map = new HashMap();
map.put("id",7788);
personMapper.add100(map);
存储过程的功能能实现。
发现
用mybatis使用Oracle时,不能使用动态sql,运行提示无效的列类型。
报错解决
https://blog.csdn.net/loongshawn/article/details/50496202
https://blog.csdn.net/weixin_37562241/article/details/104615618
整合hibernate
pom.xlm
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.10.Final</version>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc14</artifactId>
<version>10.2.0.4.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>hibernate-abc</finalName>
<!--读取子配置文件-->
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
一定不要忘了后面的读取子配置文件配置。
@Test
public void test6(){
StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
SessionFactory sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
Session session = sessionFactory.openSession();
Query query = session.createQuery("from Person");
List<Person> list = query.list();
for(Person person: list)
System.out.println(person);
}
发现
使用hibernate框架时,<id name="id"> <generator class="native"></generator> </id>
,这里用了native,hibernate会自动为使用的表创建一个序列hibernate_sequence,它会自动的从1开始,这点要注意。
Oracle数据库使用hibernate框架,在进行增删改操作一定要手动提交事务,使用mybatis框架不用手动提交事务。
测试
import ...
/**
* @className OracleHbnTest
* @date 2021/4/8 19:12
* @description
**/
public class OracleHbnTest {
@Test
public void test1(){
StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
SessionFactory sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
Session session = sessionFactory.openSession();
System.out.println(session.get(Person.class, 1));
session.close();
}
@Test
public void test2(){
StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
SessionFactory sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
Session session = sessionFactory.openSession();
//使用hibernate一定要手动提交事务
Transaction transaction = session.beginTransaction();
Person person = new Person();
person.setName("Nidalee");
person.setAge(38);
session.save(person);
transaction.commit();
session.close();
}
@Test
public void test4(){
StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
SessionFactory sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Person person = session.load(Person.class, 3);
person.setName("Miss Fortune");
session.update(person);
transaction.commit();
session.close();
}
@Test
public void test5(){
StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
SessionFactory sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Person person = session.load(Person.class, 8);
session.delete(person);
transaction.commit();
session.close();
}
@Test
public void test6(){
StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
SessionFactory sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
Session session = sessionFactory.openSession();
Query query = session.createQuery("from Person");
List<Person> list = query.list();
for(Person person: list)
System.out.println(person);
}
}
CRUD的操作完全正常。hibernate框架确实有它的强大之处。
Mysql数据库
首先方便的是MySQL的主键可以设置为自增,这个方便用户使用,无论整合mybatis还是hibernate都不用过多关心主键。
其次MySQL数据库是以数据库为基本单位,一个用户可以有多个数据库,然后数据库中可以有多个表。
创建数据库
主要的数据类型
经常用的:
char:大小0-255bytes,定长字符,varchar:大小0-65535bytes,可变长字符,这两种一般用于存储String类型的字段。
date:大小3bytes,DATETIME:8个byte。
INT或INTEGER,4bytes,float,4bytes,double:8bytes
详情请看:https://www.runoob.com/mysql/mysql-data-types.html
CREATE TABLE `usera` (
`id` int(32) NOT NULL AUTO_INCREMENT,
`name` char(10) DEFAULT NULL,
`age` int(32) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8
整合Mybatis框架
这里除了平时用到的之外,我最想记录的就是MySQL配合mybatis使用动态sql语句。
<!-- 根据条件查询-->
<select id="findUserByCondition" resultType="user">
<!--select * from usera where 1=1
<if test="name != null">
and name = #{name}
</if>
<if test="age != 0">
and age = #{age}
</if>-->
select * from usera
<where>
<if test="name != null">
and name = #{name}
</if>
<if test="age != 0">
and age = #{age}
</if>
</where>
</select>
<select id="findUserInIds" resultMap="userMap" parameterType="com.example.bean.QueryVo">
<include refid="defaultSelect"></include>
<where>
<if test="ids != null and ids.size()>0">
<foreach collection="ids" open="and id in (" close=")" item="uid" separator=",">
#{uid}
</foreach>
</if>
</where>
</select>
使用MySQL一定要注意高版本的配置问题
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///xxxx?useSSL=false&serverTimezone=UTC"/>
url要加上时区和不使用安全协议。
Mybatis作为一种半自动型的框架,感觉它的优势就是能让用户写出适合的sql语句,所以才在国内比较流行吧。
整合Hibernate框架
还是要注意配置。
<!-- 初始化JDBC连接-->
<session-factory>
<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql:///test?useSSL=false&serverTimezone=UTC</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<property name="dialect">org.hibernate.dialect.MySQL8Dialect</property>
<property name="show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!--关联对象映射配置文件-->
<mapping resource="com/example/domain/Account.hbm.xml"></mapping>
</session-factory>
在不使用spring框架的情况下,要读取配置hibernate.cfg.xml文件
@Test
public void test1(){
// 获取服务注册对象
StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
// 默认加载hibernate.cfg.xml,如果名字不一样,要写出来
.configure()
.build();
// 从元数据获取session对象
MetadataSources metadataSources = new MetadataSources(registry);
// 获取session工厂
SessionFactory sessionFactory = metadataSources.buildMetadata().buildSessionFactory();
Session session = sessionFactory.openSession();
Account account = new Account();
account.setName(TestHibernate.getRandomString(5));
account.setMoney(TestHibernate.getRandomNumber(4));
session.save(account);
session.close();
}
MySQL使用hibernate不用手动提交事务,这一点令我非常惊奇。
这里我一直使用xml配置的方式,而没用注解配置的方式,虽然会多几个文件,但我个人认为使用配置文件能让管理和维护更统一一些。
写在后面
或许这些知识还很浅薄,但不积小流无以成江海,不积跬步无以至千里,