(Oracle真的是走哪祸害到哪23333)javascript
Java多用MySQL和Oraclejava
SQLServer也收费,可是还行,比Oracle便宜,一个差很少3w多python
SQLite被嵌入到了安卓系统中,主要用于安卓开发,是彻底免费的mysql
关于MySQL收费的问题,这篇文章说的很透:git
你使用开源软件并不受GPL约束,只有在你基于开源软件,修改开源软件的源码的时候才受 GPL约束。MySQL做为一个开源数据库,几乎全部的用户都只是经过本身的程序去操做这个数据库,不涉及到改动源码的问题,根本不用去考虑是否要遵循 GPL的问题。只有在你修改MySQL源码的状况下,才须要考虑GPL。github
若是你只是使用MySQL而不是改写MySQL,那么在这些状况下你应该考虑购买Oracle的商业版本,一是Oracle的商用版本提供的附加组件(监控器、备份工具等)对你有价值,二是Oracle的年度技术支持是你须要的,三是各类潜规则。而不该该是你想合法的使用MySQL才去购买其商业版本。另外,若是你是基于MySQL的源码开发你本身的产品,那么你须要购买的是商业受权,而不是subscription这些商业版本。sql
除了以上状况,使用社区版就好shell
关闭服务须要使用管理员权限数据库
服务器没法链接时,要检查服务是否正常开始了数组
登陆MySQL:
mysql -uroot -proot
//u表明user,后面的root是用户名,p表明password,后面的root是密码
退出:exit/quit
登陆其余电脑的MySQL
mysql -h127.0.0.1 -uroot -proot//这里的127.0.0.1应该替换为对应的服务器ip地址
也能够这样:
mysql --hosst=ip --user=root --password=root
bin:二进制可执行文件
include:C语言的头信息
lib:运行所须要的库文件
share:错误记录
这个目录在C盘隐藏的文件夹ProgramData里面
my.ini是MySQL的配置文件
数据存放的位置:
MySQL shell:mysql-shell是一个高级的mysql命令行工具、它直接两种模式(交互式&批处理式)三种语言(javascript\python\sql),格式为JSON。MySQL是在官方版本5.7.12推出,工具的初衷自己都是为了解决一类问题,想必官方从不少方面了解到工具的使用状况,支持的开发语言太多,众口难调,因此这么个命令行工具就出来了
日常对数据库的操做使用Command Line Client其实就行了
注释必定要带空格,命令都要以分号结尾
------
information_schema:描述数据库的信息,存放的是视图而不是表,不存在真正对应的物理文件
mysql:核心数据库,存放表文件
performance_schema:对性能提高作操做
上面的三个数据库都要求不要贸然修改,不然可能会影响数据库稳定性
(查询数据库的建立语句,能够查看数据库的字符集)
不能建立重名数据库
注意,建立表的时候,对于表名和Entity的名称用的是`,而不是单引号
先判断,再建立
选择使用特定字符集的数据库
总结,关于数据库的建立:
若是数据库不存在,删除会报错,能够先判断是否存在再删除
注意应该写utf8而不是utf-8
数据类型:
这里要认识一个单词:alter(修改)
修改列明部分,应该是“新列名”而不是“新列别”
引号单双均可以
TRYNCATE是直接所有删除,而delete是一条一条删,TRUNCATE效率更高
null参与的运算结果都是null(null就是unkown,计算结果固然也是unkown了)
起别名:
注意这里的等号是一个的,不要写成==
<>和!=同样,是不等于的意思
&& 和 AND等效
NULL不能用等号去判断,只能用is
NOT放在IS后面
查询优化:
注意,这个操做对于不一样的软件不同,这里只是MySQL中的方法
DBA:数据库管理员,对数据库专门负责
mysql这个数据库是不显示在workbeach上的
题外话:在SQL指令中,若是只想执行script中的某一条或者某几条指令,应该用鼠标将其选起来,这样其余指令就不会执行了
注意,%通配符在主机名这一栏也是可使用的,能够用来表示全部主机。
修改密码:
注意数据库中的密码是加密的,在查看时候也看不到原密码,修改密码时须要使用PASSWORD()函数来对要设置的密码进行加密
root用户的密码忘记了也有方案!
惟一约束并不要求NULL惟一
主键:非空且惟一,惟一标识
基于主键约束的自动增加
MySQL 每张表只能有1个自动增加字段,这个自动增加字段便可做为主键,也能够用做非主键使用,可是请注意将自动增加字段当作非主键使用时必须为其添加惟一索引,不然系统将会报错。例如:
– 将自动增加字段设置为主键
create table t1 (id int auto_increment Primary key,sid int);
– 将自动增加字段设置为非主键,注意必须显式添加Unique键
create table t2 (sid int primary key,id int auto_increment Unique);
– 将自动增加字段设置为非主键若是未添加惟一索引将会报错,以下面语句
create table t3 (sid int primary key,id int auto_increment);
这里放在主键里面讲,只是由于大多数状况下自动增加都是用在主键上面的
自动增加只和上一条有关系,若是人工插入改变了序号,则下一条会接着上一条进行
设置了自动增加的列通常输入NULL就能够了,输入具体数字会改变原有排序
表之间的关联,能够用来消除冗余数据。
通常外键都关联主表的主键
被关联的表必定要先于主动进行管理的表完成建立
被关联的表在引用解除以前不能被删除,要删除或者修改就必须先解除引用,解除引用不必定是指要删除外键,将调用该对象的那个键指向其余或者是NULL就行了
外键约束会自动要求必须存在,但能够为NULL
注意,外键添加在表建立的末尾,而且会再起一个外键名(这里涉及到了三个名字),以后的删除也是删除这种约束自己,而不是删除被加在其上的列
外键的级联:能够更方便地修改被调用的键值,更改会直接体如今被调用表上
级联包括更新和删除两个方面
级联删除有点危险,并且效率不高
因此,实际开发中,级联的使用是很谨慎的
表是现实的抽象
数据库设计涉及到多表关系和范式(数据库设计准则)两个方面
一对多:在多的一方创建外键,指向一的一方的主键
多对多:创建中间表,中间表至少有两个字段,分别指向两张表的主键(联合主键)
一对一:一对一关系的实现,能够在任意一方添加惟一外键指向另外一方的主键
? 可是!通常状况下,若是遇到一对一的关系,通常状况下都会直接合成一张表而不是两张表
如何在workbeach中生成EER图
>
---
越高范式冗余越小
通常来讲,遵照了前三种范式,数据库设计就没有太大问题了
第N范式都是以遵循前面的范式为基础的,因此,范式分析都是从前至后的
每一列都是不可分割的原子数据项
这种是不符合第一范式的
修改成没有复合列的状况就行了
上面的表格存在的问题:
例如上面的例子,(学号,课程名称)称为组,这两个属性也被称为主属性,分数这个非主属性是彻底依赖于组的,而姓名、系名和系主任这三个非主属性只依赖于学号,这就不符合第二范式了。
如何修改?拆分表
A表中,主属性是学号和课程名称;B表中,主属性是学号
依然没有解决的问题:
例如上面的B表中,姓名被系名依赖,而系名被系主任依赖,这就是传递依赖
解决方法?再分表
刚刚全部的问题就所有解决了
通常地,每一天咱们都须要对数据进行备份
多表查询出来的是笛卡尔积结果(M*N)
通常会对不一样表起别名来便于写指令
SQL通常写成多行以便于阅读:
最规范的写法
另外一种写法:
如何写子查询?能够先分开写多条(如上),而后合为一条
查询结果为多行多列的状况,实际上就是将第一次查询出来的结果做为一张暂存的表再和其余表进行组合等操做
控制台cmd默认操做是gbj,数据是utf8,中文字符可能会有显示问题
事务不提交以前是不会对数据库数据出现修改的,若是关闭窗口会自动回复事务前的状况
MySQL中事务默认自动提交,选择START TRANSACTION以后切换到手动提交模式,COMMIT命令以前是不会提交的。固然,咱们也能够查看和修改事务的默认提交方法(1:自动提交,0:手动提交)注意,Oracle是手动提交的
对于MySQL,使用手动提交事务正确的操做方式为:
多个事务之间,咱们想要努力作到隔离,虽然经常不能彻底隔离
事务的一致性是创建在事务每每的应用背景下的
注意,幻读这里的描述不许确,不是“查询不到本身的修改”,而能够描述为“发现本身的修改没有应用到全部记录上(也就是说有例外)"
MySQL默认隔离级别为repeatable read,而Oracle是read committed
查询和设置隔离级别:
Java数据库链接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。 JDBC也是Sun Microsystems的商标。 JDBC是面向关系型数据库的。
Java定义了一套操做全部关系型数据库的规则(接口),具体的实现由各自的数据库软件负责,从而实现用一套统一的Java代码操做全部的关系型数据库,即以接口类型调用方法,真正实现的是实现类中的方法
JDBC快速入门:
package com.jiading.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; //JDBC入门 public class JDBCDemo1 { public static void main(String[] args) throws Exception { //导入驱动jar包 //注册驱动 Class.forName("com.mysql.cj.jdbc.Driver"); //获取数据库链接对象 Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/jd1?serverTimezone=UTC","root","root"); //定义SQL语句 String sql="update test set figure1 =10 where figure2=3"; Statement stmt=conn.createStatement(); //执行SQL int count=stmt.executeUpdate(sql); System.out.println(count); stmt.close(); conn.close(); } }
Class.forName()将类的字节码文件加载到内存中
这里注意注册驱动部分的路径怎么写,首先须要先导入jar包,从网络中下载mysql-connect的jar包,将其导入IDEA。导入的过程以下:
先说下第一种方法吧。也就是
File –> Project Structure导入方法
先是进入:File –> Project Structure
(Error:This picture is not found in the List!)>
再找到Modules->Dependencies
点击最右侧的绿色+号
如图:(Error:This picture is not found in the List!)>
选择1或者2都行的:(Error:This picture is not found in the List!)>
而后就是选择你要导入的Jar包了。而后再讲下第二种方式。
右键添加Jar包
也就是在你须要导入的Jar包上,点击右键,选择Add as Library…
(Error:This picture is not found in the List!)>
点击OK就好了。(Error:This picture is not found in the List!)
以后按着jar包的目录输入:
题外话,URL中,?被用来分割URL自己和参数,例如这里URL中加入的serverTimezone=UTC就是由于链接时出现了异常“The server time zone value '?й???????' is unrecognized or represents more than one time zo”
在使用Class.forName()将该Driver类加载到内存时,静态代码块被执行,调用DriverManager的静态方法registerDriver进行了驱动的注册,因此以后咱们才能直接调用DriverManager的静态方法使用。
省略注册驱动指的是Class.forName能够省略了:驱动jar包在没有注册驱动时,自动读取META-IN\services下的java.sql.Driver文件进行注册
MySQL默认的端口号是3306
Statement执行的静态SQL,PreparedStatement能够执行动态SQL
不常常用statement执行DDL:由于Connection是创建在数据库上的(即URL中有具体的数据库),因此不能用这个命令来处理数据库,而即便是表的设计也是一个很负责的过程,通常都是用SQL的软件完成的,不多用代码直接完成。
刚才代码存在的问题:
示例代码以下:
package com.jiading.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; //JDBC入门 public class JDBCDemo2 { public static void main(String[] args) { //导入驱动jar包 //注册驱动 Statement stmt=null; Connection conn=null; try { Class.forName("com.mysql.cj.jdbc.Driver"); String sql="update test set figure1 =10 where figure2=3"; try { conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/jd1?serverTimezone=UTC","root","root"); stmt=conn.createStatement(); int count=stmt.executeUpdate(sql); System.out.println(count); if(count>0){ System.out.println("添加成功!"); } else{ System.out.println("添加失败"); } } catch (SQLException e) { e.printStackTrace(); } } catch (ClassNotFoundException e) { e.printStackTrace(); }finally{ /* 先释放stmt,再释放conn,由于stmt是由conn建立的 为了可以在finally中释放这两个变量,须要将它们定义在try以前,先赋值为Null(这个术语叫变量的抽取) 一样的,为了不空指针异常,咱们须要在释放前先判断,若是是null就不释放了 */ if(stmt!=null) { try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn!=null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } //获取数据库链接对象 //定义SQL语句 //执行SQL } }
注意,这里的注释有错位
executeupdate方法不只能够执行DML,还能够执行DDL语句,对表进行修改
其实就是对查询的结果的封装。
ResultSet游标:查询开始时指向表第一行的上一行
next():游标向下一行。注意,这里移动游标获取以前必定要先加一个判断,判断是否有数据。这个判断不须要咱们去写,而是next方法本身就会返回的:next方法是一个boolean类型的方法,若是调用了以后当前行没有数据其会返回null,不然会返回true。以此为条件就能判断了。将next方法写在while中,还能够实现循环遍历
getXXX(参数):XXX表明数据类型,这是获取数据的方法,例如getInt\getString等。注意,获取数据时不是把一行的全部数据都获取了,而是只获取某一列的数据
其中参数能够接受Int或者String。传入Int表明获取该行中第几列的值(注意,这里特殊的是,标号是从1开始的),传入String则是具体的指明获取的列的label.
定义一个方法,查询emp表的数据将其封装为对象,而后装载集合,返回
代码以下:
package com.jiading.jdbc; /* 封装emo表数据的JavaBean */ public class Jd1{ private int day; private int year; public int getYear() { return year; } public void setYear(int year) { this.year = year; } public int getDay() { return day; } public void setDay(int day) { this.day = day; } @Override public String toString() { return "JDBCDemo3{" + "year=" + year + ", day=" + day + '}'; } }
package com.jiading.jdbc; import java.sql.*; import java.util.ArrayList; import java.util.List; public class JDBCDemo3 { public static void main(String[] args) { //这里又用到了匿名内部类,而且这里的类仍是咱们写的这个java类 List<Jd1>e=new JDBCDemo3().findall(); System.out.println(e); } public List<Jd1> findall(){ /* 查询全部Jd22对象 */ /* 若是将对象的建立写在循环内,会产生许多引用。 此时的一个优化策略是将引用写在外面,先赋值为null,在循环中每次new新对象便可 */ Jd1 re=null; List<Jd1>list=null; Connection conn=null; Statement stmt=null; ResultSet rs=null; try { Class.forName("com.mysql.jdbc.Driver"); conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/jd1?serverTimezone=UTC","root","root"); String sql="select * from test"; stmt=conn.createStatement(); rs=stmt.executeQuery(sql); /* 这里注意,List在Java中是一个抽象类,是不能直接实例化的,而ArrayList则是对List的一种实现,实际实例化的经常是ArrayList */ list=new ArrayList<Jd1>(); while(rs.next()){ int year=rs.getInt("year"); int day=rs.getInt("day"); re=new Jd1();//引用绑定到新对象上 re.setDay(day); re.setYear(year); list.add(re); } } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); }finally{if(conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } if(stmt!=null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if(rs!=null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } } return list; } }
Sql注入问题:
如图,and和or都是左结合的,最后and是嵌套在or里面的
解决:使用PreparedStament对象
PreparedStament是Statement的子接口,可是其是预编译的SQL:参数使用占位符替代,例如:
select * from user where username =? and password=?;
获取执行sql语句的对象 PreparedStatemnet connnection.preparedStatment(string sql);//和获取statement不一样,获取PreparedStatement对象是要传参数的
因为咱们的sql中内容是以占位符形式代替的,因此将sql传入后须要先给它赋值(先传再赋值)
实际状况下使用的大多都是PreparedStatement来完成增删查改,它不只能够防止SQL注入,并且效率更高
这个是本身搭建的,用于简化重复的代码
其实Connection也是工具类,工具类有个特色,就是全部的方法都是静态的,以便咱们进行调用具体的方法解决问题,而不至于一直关注于对象的建立(例如String类的valueof方法就是静态的,目的是为了其余类型向String的转化)。因此,咱们在写的时候也这样作。
步骤:
注意,不是每一次使用咱们都须要注册驱动的,因此注册驱动的部分咱们写成一个单独的方法,须要的时候再调用
事务的管理是由Connection对象完成的
这里catch的是一个大的异常,以便于在遇到各类问题的时候都回滚。固然,咱们须要先判断一下conn是否是null,由于可能在conn实例化以前就发生了异常,此时就不须要回滚了。
链接对象用完了不释放,而是放入链接池,以后须要直接调用
接口由Sun公司定义,由数据库方实现
实现:
对于用户来讲,归还和以前使用的销毁对象是没有区别的
这个东西通常咱们不去实现,而是由数据库厂商实现
今天讲解两种不一样的实现形式:
使用起来有两种方法:硬编码和配置文件,通常推荐使用配置文件方法,以加强通用性
注意开发环境,jar包的版本
c3p0-config.xml必须放在src根目录下
配置文件参数讲解:
最大链接数:同时能使用的最大链接数量
<default-config>和<named-config name="otherc3p0">的区别: c3p0容许用户在配置文件中保存多种配置,使用name进行区分,在new ComboPolledDataSource()时若是括号什么都不写,就使用默认配置;要是括号写了name的字符串,就使用对应的配置
注意,druid和C3P0相比:
有些框架不须要获取链接池对象,只须要链接池便可,因此要加上获取链接池的方法
Spring JDBC
使用Junit单元测试:可让方法独立执行,而再也不依赖于主方法。须要在以前加一个@Test.最重要的是,这样咱们就能够建立多个方法,分别对其进行调试,而相互之间不会影响,也不须要主方法,很是利于调试
能够将获取JdbcTemplate的部分做为成员变量,这样就不须要每一个方法都获取一次了。
注意,queryForMap()查询的结果集长度只能是1:若是本次查询会返回两个及以上结果,则会报错。因此若是结果有多是多个,应该使用queryForList()或者query()
queryForList()是将每一条记录封装为一个map集合,再将map装载到List中
若是要将查询结果封装为其余类型,就使用query()方法,在传入sql的同时再传入RowMapper接口类型的对象,这里咱们本身本身实现一下:
最重要的是要实现一下RowMapper的mapRow方法
注意,咱们在本身实现的时候就能够填要返回的类型了,这里填的是需求中的Emp类(泛型)。
而RowMapper也本身提供了一些实现类,有的是很经常使用的,不须要每次都本身去实现。
这里的泛型填本身要返回的类型就行了,固然,咱们的类的属性要和所查询的属性名称以及类型相一致。
这里有一个常见的问题:咱们在定义类的时候若是使用的是基本数据类型,那么它是不能接受Null的,这样在sql中就可能会有问题:由于有些数据库中的数据返回的就是null,因此咱们应该使用引用数据类型,例如Int、Double等。
对于queryForObject()方法,咱们初始化时要输入返回的结果的类型,例如这里的Long.class,返回的就是Long这个类。