创建一个存储过程purchase_proc,实现购买一个商品的业务逻辑两个传入参数

通过Java如何去使用数据库来帮助我们存储数据呢,这将是本章节讨论的重点。

JDBC是什么?JDBC英文名为:Java Data Base Connectivity(Java数据库连接),官方解释它是Java编程语言和广泛的数据库之间独立于数据库的连接标准的Java API,根本上说JDBC是一种规范,它提供的接口,一套完整的,允许便捷式访问底层数据库。可以用JAVA来写不同类型的可执行文件:JAVA应用程序、JAVA Applets、Java Servlet、JSP等,不同的可执行文件都能通过JDBC访问数据库,又兼备存储的优势。简单说它就是Java与数据库的连接的桥梁或者插件,用Java代码就能操作数据库的增删改查、存储过程、事务等。

一个Java程序并不是一个人的战斗,我们可以在别人开发的基础上继续向上开发,其他的开发者可以将自己编写的Java代码打包为jar,我们只需要导入这个jar作为依赖,即可直接使用别人的代码,就像我们直接去使用JDK提供的类一样。

使用JDBC连接数据库

**注意:**/ 进行查询(可能打不开,建议用流量,或是直接百度某个项目的Maven依赖),我们直接搜索lombok即可,打开后可以看到已经给我们写出了依赖的坐标:

这样,我们就将默认的远程仓库地址(国外),配置为国内的阿里云仓库地址了(依赖的下载速度就会快起来了)

除了三个基本的属性用于定位坐标外,依赖还可以添加以下属性:

  • type:依赖的类型,对于项目坐标定义的packaging。大部分情况下,该元素不必声明,其默认值为jar
  • scope:依赖的范围(作用域,着重讲解)
  • optional:标记依赖是否可选
  • exclusions:用来排除传递性依赖(一个项目有可能依赖于其他项目,就像我们的项目,如果别人要用我们的项目作为依赖,那么就需要一起下载我们项目的依赖,如Lombok)

我们着重来讲解一下scope属性,它决定了依赖的作用域范围:

  • compile :为默认的依赖有效范围。如果在定义依赖关系的时候,没有明确指定依赖有效范围的话,则默认采用该依赖有效范围。此种依赖,在编译、运行、测试时均有效。
  • provided :在编译、测试时有效,但是在运行时无效,也就是说,项目在运行时,不需要此依赖,比如我们上面的Lombok,我们只需要在编译阶段使用它,编译完成后,实际上已经转换为对应的代码了,因此Lombok不需要在项目运行时也存在。
  • runtime :在运行、测试时有效,但是在编译代码时无效。比如我们如果需要自己写一个JDBC实现,那么肯定要用到JDK为我们指定的接口,但是实际上在运行时是不用自带JDK的依赖,因此只保留我们自己写的内容即可。
  • test :只在测试时有效,例如:JUnit,我们一般只会在测试阶段使用JUnit,而实际项目运行时,我们就用不到测试了,那么我们来看看,导入JUnit的依赖:

同样的,我们可以在网站上搜索Junit的依赖,我们这里导入最新的JUnit5作为依赖:

我们可以看到,IDEA默认给我们添加了一个parent节点,表示此Maven项目是父Maven项目的子项目,子项目直接继承父项目的groupId,子项目会直接继承父项目的所有依赖,除非依赖添加了optional标签,我们来编写一个测试用例尝试一下:

可以看到,子项目也成功继承了Lombok依赖。

我们还可以让父Maven项目统一管理所有的依赖,包括版本号等,子项目可以选取需要的作为依赖,而版本全由父项目管理,我们可以将dependencies全部放入dependencyManagement节点,这样父项目就完全作为依赖统一管理。

我们发现,子项目的依赖失效了,因为现在父项目没有依赖,而是将所有的依赖进行集中管理,子项目需要什么再拿什么即可,同时子项目无需指定版本,所有的版本全部由父项目决定,子项目只需要使用即可:

当然,父项目如果还存在dependencies节点的话,里面的内依赖依然是直接继承:

我们可以看到在IDEA右上角Maven板块中,每个Maven项目都有一个生命周期,实际上这些是Maven的一些插件,每个插件都有各自的功能,比如:

  • clean命令,执行后会清理整个target文件夹,在之后编写项目时可以解决一些缓存没更新的问题。
  • validate命令可以验证项目的可用性。
  • install命令可以将当前项目安装到本地仓库,以供其他项目导入作为依赖使用

通过使用test命令,可以一键测试所有位于test目录下的测试案例,请注意有以下要求:

  • 测试类的名称必须是以Test结尾,比如MainTest

这是由于JUnit5比较新,我们需要重新配置插件升级到高版本,才能完美的兼容Junit5:

我们的项目在编写完成之后,要么作为Jar依赖,供其他模型使用,要么就作为一个可以执行的程序,在控制台运行,我们只需要直接执行package命令就可以直接对项目的代码进行打包,生成jar文件。

当然,以上方式仅适用于作为Jar依赖的情况,如果我们需要打包一个可执行文件,那么我不仅需要将自己编写的类打包到Jar中,同时还需要将依赖也一并打包到Jar中,因为我们使用了别人为我们通过的框架,自然也需要运行别人的代码,我们需要使用另一个插件来实现一起打包:

在打包之前也会执行一次test命令,来保证项目能够正常运行,当测试出现问题时,打包将无法完成,我们也可以手动跳过,选择执行Maven目标来手动执行Maven命令,输入mvn package -Dmaven.test.skip=true来以跳过测试的方式进行打包。

最后得到我们的Jar文件,在同级目录下输入java -jar xxxx.jar来运行我们打包好的Jar可执行程序(xxx代表文件名称)

  • deploy命令用于发布项目到本地仓库和远程仓库,一般情况下用不到,这里就不做讲解了。
  • site命令用于生成当前项目的发布站点,暂时不需要了解。

我们之前还讲解了多模块项目,那么多模块下父项目存在一个packing打包类型标签,所有的父级项目的packing都为pom,packing默认是jar类型,如果不作配置,maven会将该项目打成jar包。作为父级项目,还有一个重要的属性,那就是modules,通过modules标签将项目的所有子项目引用进来,在build父级项目时,会根据子模块的相互依赖关系整理一个build顺序,然后依次build。


  • 在线录入学生信息和书籍信息
}

存储过程和函数的区别?

存储过程 是一段代码(过程),存储在数据库中的SQL组成。一个存储过程通常用于完成一段业务逻辑;
函数通常是数据库已定义的方法。
存储过程和函数执行不是由程序调用,也不是手动启动。而是由事件触发、激活从而实现执行。
一个函数通常专注与某个功能,视为其他程序服务的,需要在其他语句中调用函数才可以,而存储过程不能被其他调用,是自己执行通过call执行。
存储过程和函数都是属于某个数据库。
函数有一个返回值,而存储过程是通过参数返回的,可以有多个或者没有。
函数一般情况下是用来计算并返回一个计算结果,而存储过程一般是用来完成特定的数据操作。
oracle中存储过程和函数都可以返回值,但是函数必须要返回值并且一般返回一个值,而存储过程则没有这个限制。

查看对应数据库下所有存储过程状态

查看名称包含Student的存储过程状态

注:不能在一个存储过程中删除另一个存储过程,只能调用另一个存储过程。
mysql存储过程用call和过程名以及一个括号,括号里面根据需要,加入参数,参数包括输入参数、输出参数、输入输出参数调用。

DELIMITER $$ --定义结束符。MySQL默认的结束符是分号,但是函数体中可能用到分号。为 了避免冲突,需要另外定义结束符。
 
 


 
-- 计划频率和开启计划时间或者是计划执行的时间 -- 前一个可以实现持续的计划调度,后一个到指定时间进行调度,执行完结束,没有持续性 -- 当计划执行完成时,是否删除 ---查看数据库是否开启调度 -- 查看是否开启调度 --关闭和开启指定定时器
--定时器创建好后,会自动执行。 --查看在执行的定时器,job-定时器编号
 
触发器组成:
1、触发事件---DML或DDL语句。
2、触发时间---是在触发事件发生之前(before) 还是之后(after) 触发
3、触发操作---使用PL/SQL块进行相应的数据库操作
4、触发对象---表、视图、模式、数据库
5、触发频率---触发器内定义的动作被执行的次数,包括语句级和行级。

MySQL
触发器是按照BEFORE触发器、行操作、AFTER触发器的顺序执行的,其中任何一步发生错误都不会继续执行剩下的操作。如果是对事务表进行的操作,那么会整个作为一个事务被回滚,但是如果是对非事务表进行的操作,那么已经更新的记录将无法回滚,
Oracle
触发器:类似于AOP(面向切面编程)中的拦截器;不能传递参数,输出参数,也不能显示调用,只有满足触发器条件时会由Oracle自动调用。
限制
1、触发器不接受参数
2、一个表上最多可有12个触发器,但同一时间、同一事件、同一类型的触发器只能有一个。并各触发器之间不能有矛盾。
3、一个表上的触发器越多,该表上的DM操作的性能影响就越大
4、触发器代码的大小不能超过32K。如需要大量的代码创建触发器,则首先创建过程,然后在触发器中使用CALL语句调用过程
5、触发器代码只能包含SELECT、INSERT、UPDATE和DELETE语句,
6、不能包含DDL语句(CREATE、ALTER和DROP) 和事务控制语句(COMMIT、ROLLBACK和SAVEPOINT)
语句触发器
1、语句触发器是指当执行DML语句时被隐含执行的触发器
2、如果在表上针对某种DML操作创建了语句触发器,则当执行DML操作时会自动地执行触发器的相应代码
3、为了审计DML操作,或者确保DML操作安全执行时,可以使用语句触发器
触发器用途很多,例如用户清算购物车后将会触发待收货的数据库 --代码解释:先执行创建触发器代码后,再执行最后的更新语句。当更新恩平、表后将会输出数据库中本来存放的值,并且触发添加语句在demo表中插入一条语句。
 
MySQL:
自 MySQL5.1.6起,增加了一个非常有特色的功能–事件调度器(Event Scheduler),可以用做定时执行某些特定任务,来取代原先只能由操作系统的计划任务来执行的工作。事件调度器有时也可称为临时触发器(temporal triggers),因为事件调度器是基于特定时间周期触发来执行某些任务,而触发器(Triggers)是基于某个表所产生的事件触发的,区别也就在这里。 --查看当前是否已开启事件调度器 :
--修改要执行的操作: --修改下次执行时间:
查看日志全文:cat + 日志名称.log
-u,以用户(user)的格式显示
-x, 显示后台进程运行参数
-ef,以全格式显示进程所有信息,包括父进程Pid,创建人,创建时间,进程号。等等
 ps -l 列出与本次登录有关的进程信息;
 ps -aux 查询内存中进程信息;
 top 查看内存中进程的动态信息;
 

并行和并发有什么区别?

 
 
  1. 并行(Parallel):指两个或者多个事件在同一时刻发生,即同时做不同事的能力。例如垃圾回收时,多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。
  2. 并发(Concurrent):指两个或多个事件在同一时间间隔内发生,即交替做不同事的能力,多线程是并发的一种形式。例如垃圾回收时,用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),用户程序在继续运行,而垃圾收集程序运行于另一个CPU上。
 

线程和进程的基本概念、线程的基本状态以及状态之间的关系?

 
 
  1. 一个线程是进程的一个顺序执行流程。一个进程中的全部线程共享同一个堆空间。线程本身有一个供程序执行时的栈,一个进程中可以包含多个线程。
  2. 线程的基本状态:新建、就绪、运行状态、阻塞状态、死亡状态。
  3. 新建状态:利用NEW运算创建了线程对象,此时线程状态为新建状态,调用了新建状态线程的start()方法,将线程提交给操作系统,准备执行,线程将进入到就绪状态。
  4. 就绪状态:由操作系统调度的一个线程,没有被系统分配到处理器上执行,一旦处理器有空闲,操作系统会将它放入处理器中执行,此时线程从就绪状态切换到运行时状态。
  5. 运行状态:线程正在运行的过程中,碰到调用Sleep()方法,或者等待IO完成,或等待其他同步方法完成时,线程将会从运行状态,进入到阻塞状态。
  6. 死亡状态:线程一旦脱离阻塞状态时,将重新回到就绪状态,重新向下执行,最终进入到死亡状态。一旦线程对象是死亡状态,就只能被GC回收,不能再被调用。
 
 
  1. 守护线程又称为后台线程,它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件
  2. 正常创建的线程都是普通线程,或称为前台线程,守护线程与普通线程在使用上没有什么区别,但是他们有一个最主要的区别是在于进程的结束中。当一个进程中所有普通线程都结束时,那么进程就会结束。如果进程结束时还有守护线程在运行,那么这些守护线程就会被强制结束
  3. 在 Java 中垃圾回收线程就是特殊的守护线程
 
通俗来说:守护线程是个服务线程,准确地来说就是服务其他的线程。

创建线程有哪几种方式?

 
 
  1. 继承Thread类(真正意义上的线程类),是Runnable接口的实现。
  2. 实现Runnable接口,并重写里面的run方法。
  3. 使用Executor框架创建线程池。Executor框架是juc里提供的线程池的实现。
 
 
 
 
  1. start() 方法用于启动线程,run() 方法用于执行线程的运行时代码。
  2. 第二次调用start() 必然会抛出运行时异常
 

创建线程池有哪几种方式?

 
 
  1. newSingleThreadExecutor():它的特点在于工作线程数目被限制为 1,操作一个无界的工作队列,所以它保证了所有任务的都是被顺序执行,最多会有一个任务处于活动状态,并且不允许使用者改动线程池实例,因此可以避免其改变线程数目;
  2. newCachedThreadPool():它是一种用来处理大量短时间工作任务的线程池,具有几个鲜明特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程;如果线程闲置的时间超过 60 秒,则被终止并移出缓存;长时间闲置时,这种线程池,不会消耗什么资源。其内部使用 SynchronousQueue 作为工作队列;
  3. newFixedThreadPool(int nThreads):重用指定数目(nThreads)的线程,其背后使用的是无界的工作队列,任何时候最多有 nThreads 个工作线程是活动的。这意味着,如果任务数量超过了活动队列数目,将在工作队列中等待空闲线程出现;如果有工作线程退出,将会有新的工作线程被创建,以补足指定的数目 nThreads;
 

在 Java 程序中怎么保证多线程的运行安全?

 
 
  1. 使用手动锁 Lock。
 
9. 什么是死锁?怎么防止死锁?
 
 
当线程 A 持有独占锁a,并尝试去获取独占锁 b 的同时,线程 B 持有独占锁 b,并尝试获取独占锁 a 的情况下,就会发生 AB 两个线程由于互相持有对方需要的锁,而发生的阻塞现象,我们称为死锁。
防止死锁方法:
尽量使用 tryLock(long timeout, TimeUnit unit)的方法(ReentrantLock、ReentrantReadWriteLock),设置超时时间,超时可以退出防止死锁。
尽量使用 Java. util. concurrent 并发类代替自己手写锁。
尽量降低锁的使用粒度,尽量不要几个功能用同一把锁。
尽量减少同步的代码块。
 
  1. volatile 仅能实现变量的修改可见性,不能保证原子性;而 synchronized 则可以保证变量的修改可见性和原子性。
 
 
  1. synchronized 可以给类、方法、代码块加锁;而 lock 只能给代码块加锁。
  2. synchronized 不需要手动获取锁和释放锁,使用简单,发生异常会自动释放锁,不会造成死锁;而 lock 需要自己加锁和释放锁,如果使用不当没有 unLock()去释放锁就会造成死锁。
  3. 通过 Lock 可以知道有没有成功获取锁,而 synchronized 却无法办到。
 
 
  1. ReentrantLock 使用起来比较灵活,但是必须有释放锁的配合动作;
 
 
由于创建和销毁线程都需要很大的开销,运用线程池就可以大大的缓解这些内存开销很大的问题;可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存。
 
一般选择为Activiti作为工作流模块的引擎。
Activiti拥有更简洁健壮的接口;
Activiti拥有更友好的用户体验;
Activiti支持启动引擎后随时热部署;
Activiti拥有更友好易用的Eclipse编译插件和在线插件;
Activiti依赖更少的jar包。

rabbitmq 的消息是怎么发送的?

 
 
首先客户端必须连接到 RabbitMQ 服务器才能发布和消费消息,客户端和 rabbit server 之间会创建一个 tcp 连接,一旦 tcp 打开并通过了认证(认证就是你发送给 rabbit 服务器的用户名和密码),你的客户端和 RabbitMQ 就创建了一条 amqp 信道(channel),信道是创建在“真实” tcp 上的虚拟连接,amqp 命令都是通过信道发送出去的,每个信道都会有一个唯一的 id,不论是发布消息,订阅队列都是通过这个信道完成的。

rabbitmq怎么保证消息的稳定性?

 
 
提供了事务的功能。
通过将 channel 设置为 confirm(确认)模式。

rabbitmq怎么避免消息丢失?

 
 
消息持久化;
ACK确认机制;
设置集群镜像模式;
消息补偿机制。
 
RabbitMQ 中重要的角色有:生产者、消费者和代理:
  • 生产者:消息的创建者,负责创建和推送数据到消息服务器;
  • 消费者:消息的接收方,用于处理数据和确认消息;
  • 代理:就是 RabbitMQ 本身,用于扮演“快递”的角色,本身不生产消息,只是扮演“快递”的角色。
 
 
  • ConnectionFactory(连接管理器):应用程序与Rabbit之间建立连接的管理器,程序代码中使用。
  • Channel(信道):消息推送使用的通道。
  • Exchange(交换器):用于接受、分配消息。
  • Queue(队列):用于存储生产者的消息。
  • RoutingKey(路由键):用于把生成者的数据分配到交换器上。
  • BindingKey(绑定键):用于把交换器的消息绑定到队列上。
 
 
vhost 可以理解为虚拟 broker ,即 mini-RabbitMQ server。其内部均含有独立的 queue、exchange 和 binding 等,但最最重要的是,其拥有独立的权限系统,可以做到 vhost 范围的用户控制。当然,从 RabbitMQ 的全局角度,vhost 可以作为不同权限隔离的手段(一个典型的例子就是不同的应用可以跑在不同的 vhost 中)。

要保证消息持久化成功的条件有哪些?

 
 
  1. 消息推送投递模式必须设置持久化,deliveryMode 设置为 2(持久)。
  2. 消息已经到达持久化交换器。
  3. 消息已经到达持久化队列。
 
 
持久化的缺地就是降低了服务器的吞吐量,因为使用的是磁盘而非内存存储,从而降低了吞吐量。可尽量使用 ssd 硬盘来缓解吞吐量的问题。
 
 

rabbitmq 怎么实现延迟消息队列?

 
 
  1. 通过消息过期后进入死信交换器,再由交换器转发到延迟消费队列,实现延迟功能;
 
 
集群主要有以下两个用途:
  • 高可用:某个服务器出现问题,整个 RabbitMQ 还可以继续使用;
  • 高容量:集群可以承载更多的消息量。
 
 
  • 磁盘节点:消息会存储到磁盘。
  • 内存节点:消息都存储在内存中,重启服务器消息丢失,性能高于磁盘类型。
 

rabbitmq 集群搭建需要注意哪些问题?

 
 
  • 各节点之间使用“--link”连接,此属性不能忽略。
  • 各节点使用的 erlang cookie 值必须相同,此值相当于“秘钥”的功能,用于各节点的认证。
  • 整个集群中必须包含一个磁盘节点。
 

rabbitmq 每个节点是其他节点的完整拷贝吗?为什么?

 
 
不是,原因有以下两个:
  1. 存储空间的考虑:如果每个节点都拥有所有队列的完全拷贝,这样新增节点不但没有新增存储空间,反而增加了更多的冗余数据;
  2. 性能的考虑:如果每条消息都需要完整拷贝到每一个集群节点,那新增节点并没有提升处理消息的能力,最多是保持和单节点相同的性能甚至是更糟。
 

rabbitmq 集群中唯一一个磁盘节点崩溃了会发生什么情况?

 
 
如果唯一磁盘的磁盘节点崩溃了,不能进行以下操作:
  • 不能添加和删除集群节点
 
唯一磁盘节点崩溃了,集群是可以保持运行的,但你不能更改任何东西。

rabbitmq 对集群节点停止顺序有要求吗?

 
 
RabbitMQ 对集群的停止的顺序是有要求的,应该先关闭内存节点,最后再关闭磁盘节点。如果顺序恰好相反的话,可能会造成消息的丢失。
 

kafka 有几种数据保留的策略?

 
 
kafka 有两种数据保存策略:按照过期时间保留和按照存储的消息大小保留。

kafka 同时设置了 7 天和 10G 清除数据,到第五天的时候消息达到了 10G,这个时候 kafka 将如何处理?

 
 
这个时候 kafka 会执行数据清除工作,时间和大小不论那个满足条件,都会清空数据。

什么情况会导致 kafka 运行变慢?

 
 
 

使用 kafka 集群需要注意什么?

 
 
  • 集群的数量不是越多越好,最好不要超过 7 个,因为节点越多,消息复制需要的时间就越长,整个群组的吞吐量就越低。
  • 集群数量最好是单数,因为超过一半故障集群就不能用了,设置为单数容错率更高。

}

我要回帖

更多关于 java生产者消费者 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信