首页 文章 精选 留言 我的

精选列表

搜索[基础搭建],共10000篇文章
优秀的个人博客,低调大师

[源码]Python Tkiner 写的截图小工具 实现了大部分基础功能

最近在写一些小工具,因为是给别人用的需要界面,刚开始使用pyQT5 功能强大,但是打包后一个小工具 就有几十兆 有点蛋疼而且还很消耗资源;后面改用TK,TK明显简洁很多,功能同样也若很多! 因为有截图需求,就抽空写了这个工具,全当练习。过程当中遇到过好多蛋疼的事情,功能基本实现后发出来给大家分享一下,我个人还是比较喜欢python这门语言的! 实现思路:3.1.新建一个最小化窗口,利用线程启动监听"ctrl+a"启动截图窗口3.2.截图窗口初始化时利用 pyautogui.screenshot 截取全屏(类似PRTSC)作为子窗口的背景(在这搞了好久,后面没办法只有利用canvas设置背景),子窗口最大化取消菜单栏3.3.在主窗口上的canvas上用绑定鼠标事件,根据鼠标选取截图范围,和鼠标操作相关功能3.4.保存功能是根据截图范围重新截图生成文件保存 代码 main_UI.py fromtkinter.messageboximportshowinfo fromSc_Tool.Sc_Winimport* importkeyboard import_thread scwd=None #新建窗口对象 win=Tk() #最小化主窗口 win.wm_state('icon') win.iconify() #启用热键‘Ctrl+a’截屏 defstar_sc(): globalscwd scwd=windSc(win) scwd.newwind() defexit_sc(): print("exit") scwd.exit_sc(scwd) defstartThread1(event=None): keyboard.add_hotkey('ctrl+a',star_sc,args=(),suppress=False) defstartThread2(event=None): keyboard.add_hotkey('esc',exit_sc,args=(),suppress=False) try: _thread.start_new_thread(startThread1,()) _thread.start_new_thread(startThread2,()) exceptExceptionase: print(e) #启动app win.mainloop() scwd=None #新建窗口对象 win=Tk() win.wm_state('icon') win.iconify() #启用热键‘Ctrl+a’截屏 defstar_sc(): globalscwd scwd=windSc(win) scwd.newwind() defexit_sc(): scwd.exit_sc(scwd) defctrl_z(): scwd.ctrl_z(scwd) defstartThread1(event=None): keyboard.add_hotkey('ctrl+a',star_sc,args=(),suppress=False) defstartThread2(event=None): keyboard.add_hotkey('esc',exit_sc,args=(),suppress=False) defstartThread3(event=None): keyboard.add_hotkey('ctrl+z',ctrl_z,args=(),suppress=False) try: _thread.start_new_thread(startThread1,()) _thread.start_new_thread(startThread2,()) _thread.start_new_thread(startThread3,()) exceptExceptionase: print(e) #启动app win.mainloop() Sc_Tool/Sc_Win.py importos fromtkinterimport* importtkinter importpyautoguiaspyautogui fromPILimportImage,ImageTk importtkinter.fontastkFont importtime classwindSc: win,file_path,im,winAppSc,mouEvent,canvas=None,None,None,None,None,None #窗口宽窗口高宽高截图起点x坐标截图起点y坐标绘图起点x坐标绘图起点y坐标 win_w,win_h,width,height,x,y,dx,dy=0,0,0,0,0,0,0,0 #截图结束点坐标 end_x,end_y=0,0 #开始添加图形的起始坐标 cr_x,cr_y=0,0 #记录按钮的状态、文本输入按钮状态 but1_stat,but_text_stat=False,False #记录按钮类型1矩形2圆形 but_type=0 #tag标记文本输入单击次数标记 i,p=1,0 #工具栏部件 but1,but2,but3,but4,buttext,text_lable=None,None,None,None,None,None #画笔大小,文本框行数 size,row=1,1 #画笔颜色 color="black" #字体 font=None #按钮图片 img1,img2,img3,imgs,imgp1,imgp2,imgp3=None,None,None,None,None,None,None imgred,imgwhite,imgblack,imgblue,imggreen,imgyellow,imgback=None,None,None,None,None,None,None #工具按钮列表 but_list=[] #图形id列表 ids=[] def__init__(self,win): self.win=win #获取屏幕分辨率 self.width,self.height=win.winfo_screenwidth(),win.winfo_screenheight() #窗口宽度和高度 self.win_w,self.win_h=self.width,self.height image=pyautogui.screenshot(region=[0,0,self.width,self.height]).resize((self.width,self.height)) self.im=ImageTk.PhotoImage(image) self.img1=tkinter.PhotoImage(file="Sc_Tool/icon/1.png") self.img2=tkinter.PhotoImage(file="Sc_Tool/icon/2.png") self.img3=tkinter.PhotoImage(file="Sc_Tool/icon/3.png") self.imgtext=tkinter.PhotoImage(file="Sc_Tool/icon/Text.png") self.imgs=tkinter.PhotoImage(file="Sc_Tool/icon/s.png") self.imgp1=tkinter.PhotoImage(file="Sc_Tool/icon/p1.png") self.imgp2=tkinter.PhotoImage(file="Sc_Tool/icon/p2.png") self.imgp3=tkinter.PhotoImage(file="Sc_Tool/icon/p3.png") self.imgblack=tkinter.PhotoImage(file="Sc_Tool/icon/black.png") self.imgwhite=tkinter.PhotoImage(file="Sc_Tool/icon/white.png") self.imgred=tkinter.PhotoImage(file="Sc_Tool/icon/red.png") self.imggreen=tkinter.PhotoImage(file="Sc_Tool/icon/green.png") self.imgblue=tkinter.PhotoImage(file="Sc_Tool/icon/blue.png") self.imgyellow=tkinter.PhotoImage(file="Sc_Tool/icon/yellow.png") self.imgback=tkinter.PhotoImage(file="Sc_Tool/icon/b.png") defnewwind(self,event=''): #最小化主窗口 self.win.wm_state('icon') self.win.iconify() self.winAppSc=Toplevel(self.win) #winAppSc.attributes("-alpha",1) #删除标题栏 self.winAppSc.overrideredirect(True) self.winAppSc.geometry("%dx%d+%d+%d"%(self.win_w,self.win_h,(self.width-self.win_w)/2,(self.height-self.win_h)/2)) self.winAppSc.config(bg="white") self.winAppSc.title('截屏') self.winAppSc.attributes("-topmost",True) canvas=tkinter.Canvas(self.winAppSc, width=self.win_w,#指定Canvas组件的宽度 height=self.win_h,#指定Canvas组件的高度 bg='red')#指定Canvas组件的背景色 canvas.create_image(0,0,image=self.im,anchor='nw',tag=('r','r0')) canvas.pack(fill='both',expand='yes') self.canvas=canvas #工具栏部件 self.but1=Button(self.winAppSc,text="保存",image=self.imgs) self.but2=Button(self.winAppSc,text="矩形",image=self.img1) self.but3=Button(self.winAppSc,text="圆形",image=self.img2) self.but4=Button(self.winAppSc,text="箭头",image=self.img3) self.buttext=Button(self.winAppSc,text="文本",image=self.imgtext) self.but5=Button(self.winAppSc,text="返回",image=self.imgback) #画笔大小 self.sizebut1=Button(self.winAppSc,text="1",image=self.imgp1) self.sizebut2=Button(self.winAppSc,text="5",image=self.imgp2) self.sizebut3=Button(self.winAppSc,text="10",image=self.imgp3) #画笔颜色 self.color_red=Button(self.winAppSc,text="red",image=self.imgred) self.color_green=Button(self.winAppSc,text="red",image=self.imggreen) self.color_blue=Button(self.winAppSc,text="red",image=self.imgblue) self.color_yellow=Button(self.winAppSc,text="red",image=self.imgyellow) self.color_black=Button(self.winAppSc,text="red",image=self.imgblack) self.color_white=Button(self.winAppSc,text="red",image=self.imgwhite) #文本框 self.text_entry=Text(self.winAppSc,bg=None,relief=None,height=self.row,width=4) canvas.bind('',lambdaevent:self.setxy(event,canvas)) canvas.bind('',lambdaevent:self.getxy(event,canvas)) canvas.bind('',lambdaevent:self.setBtn(event,self.winAppSc)) canvas.bind('',lambdaevent:self.clear(canvas)) self.but1.bind('',lambdaevent:self.bu_save(event)) self.but2.bind('',lambdaevent:self.bu_click(event,canvas,1)) self.but3.bind('',lambdaevent:self.bu_click(event,canvas,2)) self.but4.bind('',lambdaevent:self.bu_click(event,canvas,3)) self.buttext.bind('',lambdaevent:self.bu_click_text(event,canvas)) self.sizebut1.bind('',lambdaevent:self.sizebut_click(1)) self.sizebut2.bind('',lambdaevent:self.sizebut_click(5)) self.sizebut3.bind('',lambdaevent:self.sizebut_click(10)) self.color_red.bind('',lambdaevent:self.colorbut_click("red")) self.color_green.bind('',lambdaevent:self.colorbut_click("green")) self.color_blue.bind('',lambdaevent:self.colorbut_click("blue")) self.color_yellow.bind('',lambdaevent:self.colorbut_click("yellow")) self.color_white.bind('',lambdaevent:self.colorbut_click("white")) self.color_black.bind('',lambdaevent:self.colorbut_click("black")) self.text_entry.bind('',lambdaevent:self.entry(event)) self.but5.bind('',lambdaevent:self.ctrl_z()) #先清空but_list以防止下次截图时还保存有之前的按钮而之前的按钮的父窗口已经销毁 self.but_list.clear() self.but_list.append(self.but1) self.but_list.append(self.but2) self.but_list.append(self.but3) self.but_list.append(self.but4) self.but_list.append(self.buttext) self.but_list.append(self.sizebut1) self.but_list.append(self.sizebut2) self.but_list.append(self.sizebut3) self.but_list.append(self.color_red) self.but_list.append(self.color_green) self.but_list.append(self.color_blue) self.but_list.append(self.color_yellow) self.but_list.append(self.color_white) self.but_list.append(self.color_black) self.but_list.append(self.but5) #鼠标点击调用初始化绘制截图的起点位置 defsetxy(self,event,canvas): #清空上一次鼠标事件,并设置截图的起始位置 self.mouEvent=None if(self.but1_stat): #如果超出截图区域改变起始坐标为截图起始坐标 if(event.x>self.xandevent.x<self.end_x): self.dx=event.x if(event.y>self.yandevent.y<self.end_y): self.dy=event.y else: self.x,self.y=event.x,event.y forbutinself.but_list: but.place_forget() canvas.delete(self,'j0') #文本输入操作 if(self.but_text_statandself.but_type==4): self.p=self.p+1 if(self.p%2==1): self.text_entry.delete('1.0','end') self.font=tkFont.Font(family='宋体',size=(self.size+5)*3) self.text_entry.config(font=self.font,fg=self.color,width=4,height=1) self.text_entry.place(x=event.x,y=event.y) else: canvas.create_text(self.text_entry.winfo_x(),self.text_entry.winfo_y()+15,text=self.text_entry.get(1.0,END),font=self.font,justify=LEFT,fill=self.color,anchor=W) self.text_entry.place_forget() #获取所有图形对象 self.ids=list(canvas.find_all()) defPreventOutOfBounds(self,eventx,eventy): if(eventx<self.x): eventx=self.x elif(eventx>self.end_x): eventx=self.end_x if(eventy<self.y): eventy=self.y elif(eventy>self.end_y): eventy=self.end_y returneventx,eventy #鼠标按下左键拖动时调用绘制截图的终点位置 defgetxy(self,event,canvas): #记录上一次的鼠标事件,如果按钮有按下不消除选取框矩形没有按钮按下消除上一个选取矩形 if(self.but1_stat): ifself.but_type==1: #销毁上一个鼠标暂停点绘制的图形 canvas.delete(self,"j%d"%(self.i)) #防止图形画出界 event.x,event.y=self.PreventOutOfBounds(event.x,event.y) canvas.create_rectangle(self.dx,self.dy,event.x,event.y,width=self.size,outline=self.color,tag=('j',"j%d"%(self.i))) elifself.but_type==2: canvas.delete(self,"j%d"%(self.i)) event.x,event.y=self.PreventOutOfBounds(event.x,event.y) canvas.create_oval(self.dx,self.dy,event.x,event.y,width=self.size,outline=self.color,tag=('j',"j%d"%(self.i))) elifself.but_type==3: canvas.delete(self,"j%d"%(self.i)) event.x,event.y=self.PreventOutOfBounds(event.x,event.y) canvas.create_line(self.dx,self.dy,event.x,event.y,width=self.size,fill=self.color,arrow=tkinter.LAST,tag=('j',"j%d"%(self.i))) else: #新截图框 #print("销毁截图矩形") self.mouEvent=event #删除上一个矩形 canvas.delete(self,"j0") #绘制新矩形并设置结束点坐标 canvas.create_rectangle(self.x,self.y,event.x,event.y,tag=('j','j0')) self.end_x,self.end_y=event.x,event.y self.ids=list(canvas.find_all()) #鼠标释放的时候绘制工具按钮如果上次释放鼠标左键的上一个鼠标事件是拖动则显示按钮 defsetBtn(self,event,winAppSc): #获取截图区域大小如果长宽小于5个像素则不显示按钮 w,h=event.x-self.x,event.y-self.y if(self.mouEvent!=Noneandw>5andh>5): x,y=self.x,event.y forbutinself.but_list: but.place(x=x,y=y) x=x+35 #释放鼠标新的图形动作tags标记变更 self.i=self.i+1 defbu_click(self,event,canvas,but_name): #按钮按下记录其状态为True self.but1_stat=True self.i=self.i+1 self.but_type=but_name #清除文本框 self.text_entry.place_forget() #按下鼠标右键取消截图初始化参数 defclear(self,canvas): #print("取消截图") self.i=1 self.but1_stat=False #销毁所有对象 canvas.delete(ALL) #从新加载IMG对象,此时依旧是之前的截图背景 canvas.create_image(0,0,image=self.im,anchor='nw',tag=('r','r0')) canvas.pack(fill='both',expand='yes') #隐藏按钮删除截图框 forbutinself.but_list: but.place_forget() #设置画笔大小 defsizebut_click(self,size): self.but1_stat=True self.size=size self.font=tkFont.Font(family='宋体',size=(self.size+5)*3) self.text_entry.config(font=self.font) #设置画笔颜色 defcolorbut_click(self,color): self.but1_stat=True self.color=color self.text_entry.config(fg=self.color) #退出窗口 defexit_sc(self,scwd): try: scwd.winAppSc.destroy() exceptExceptionase: print(e) defbu_click_text(self,event,canvas): #输入文本框 self.but1_stat=True self.but_text_stat=True self.but_type=4 defentry(self,event): keysym=event.keysym ifkeysym=="Return": self.row=self.row+1 self.text_entry.config(height=self.row) elifkeysym=="BackSpace": text=self.text_entry.get("%d.0"%(self.row),"%d.end"%(self.row)) iflen(text)==0: self.row=self.row-1 ifself.row<1: self.row=1 self.text_entry.config(height=self.row) else: tmp=0 foriinrange(1,self.row+1): pattern="[\u4e00-\u9fa5]+" regex=re.compile(pattern) text=self.text_entry.get("%d.0"%(i),"%d.end"%(i)) ch=regex.findall(text) chstr=''.join(ch) text_len=len(text)+len(chstr) iftext_len>=tmp:tmp=text_len if(tmp>=2):self.text_entry.config(width=tmp+3) defbu_save(self,event): image=pyautogui.screenshot(region=[self.x+1,self.y+1,self.end_x-self.x-1,self.end_y-self.y-1]) save_dir="save" ifnotos.path.exists(save_dir): os.makedirs(save_dir) t=int(time.time()) image.save("%s/%d.jpg"%(save_dir,t)) #截图完成销毁窗口 self.winAppSc.destroy() defctrl_z(self): iflen(self.ids)>2: self.canvas.delete(self.ids[-1]) self.ids.pop() 截图 源码因为打包了python环境比较大 链接:https://pan.baidu.com/s/1hND-HARBPt6mumgnvvUtqA 提取码:WLWL

优秀的个人博客,低调大师

Spring Boot 2.x基础教程:默认数据源Hikari的配置详解

通过上一节的学习,我们已经学会如何应用Spring中的JdbcTemplate来完成对MySQL的数据库读写操作。接下来通过本篇文章,重点说说在访问数据库过程中的一个重要概念:数据源(Data Source),以及Spring Boot中对数据源的创建与配置。 基本概念 在开始说明Spring Boot中的数据源配置之前,我们先搞清楚关于数据访问的这些基本概念: 什么是JDBC? Java数据库连接(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。JDBC也是Sun Microsystems的商标。我们通常说的JDBC是面向关系型数据库的。 JDBC API主要位于JDK中的java.sql包中(之后扩展的内容位于javax.sql包中),主要包括(斜体代表接口,需驱动程序提供者来具体实现): DriverManager:负责加载各种不同驱动程序(Driver),并根据不同的请求,向调用者返回相应的数据库连接(Connection)。 Driver:驱动程序,会将自身加载到DriverManager中去,并处理相应的请求并返回相应的数据库连接(Connection)。 Connection:数据库连接,负责与进行数据库间通讯,SQL执行以及事务处理都是在某个特定Connection环境中进行的。可以产生用以执行SQL的Statement。 Statement:用以执行SQL查询和更新(针对静态SQL语句和单次执行)。PreparedStatement:用以执行包含动态参数的SQL查询和更新(在服务器端编译,允许重复执行以提高效率)。 CallableStatement:用以调用数据库中的存储过程。 SQLException:代表在数据库连接的建立和关闭和SQL语句的执行过程中发生了例外情况(即错误)。 什么是数据源? 可以看到,在java.sql中并没有数据源(Data Source)的概念。这是由于在java.sql中包含的是JDBC内核API,另外还有个javax.sql包,其中包含了JDBC标准的扩展API。而关于数据源(Data Source)的定义,就在javax.sql这个扩展包中。 实际上,在JDBC内核API的实现下,就已经可以实现对数据库的访问了,那么我们为什么还需要数据源呢?主要出于以下几个目的: 封装关于数据库访问的各种参数,实现统一管理 通过对数据库的连接池管理,节省开销并提高效率 在Java这个自由开放的生态中,已经有非常多优秀的开源数据源可以供大家选择,比如:DBCP、C3P0、Druid、HikariCP等。 而在Spring Boot 2.x中,对数据源的选择也紧跟潮流,采用了目前性能最佳的HikariCP。接下来,我们就来具体说说,这个Spring Boot中的默认数据源配置。 默认数据源:HikariCP 由于Spring Boot的自动化配置机制,大部分对于数据源的配置都可以通过配置参数的方式去改变。只有一些特殊情况,比如:更换默认数据源,多数据源共存等情况才需要去修改覆盖初始化的Bean内容。本节我们主要讲Hikari的配置,所以对于使用其他数据源或者多数据源的情况,在之后的教程中学习。 在Spring Boot自动化配置中,对于数据源的配置可以分为两类: 通用配置:以spring.datasource.*的形式存在,主要是对一些即使使用不同数据源也都需要配置的一些常规内容。比如:数据库链接地址、用户名、密码等。这里就不做过多说明了,通常就这些配置: spring.datasource.url=jdbc:mysql://localhost:3306/test spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.jdbc.Driver 数据源连接池配置:以spring.datasource.<数据源名称>.*的形式存在,比如:Hikari的配置参数就是spring.datasource.hikari.*形式。下面这个是我们最常用的几个配置项及对应说明: spring.datasource.hikari.minimum-idle=10 spring.datasource.hikari.maximum-pool-size=20 spring.datasource.hikari.idle-timeout=500000 spring.datasource.hikari.max-lifetime=540000 spring.datasource.hikari.connection-timeout=60000 spring.datasource.hikari.connection-test-query=SELECT 1 这些配置的含义: spring.datasource.hikari.minimum-idle: 最小空闲连接,默认值10,小于0或大于maximum-pool-size,都会重置为maximum-pool-size spring.datasource.hikari.maximum-pool-size: 最大连接数,小于等于0会被重置为默认值10;大于零小于1会被重置为minimum-idle的值 spring.datasource.hikari.idle-timeout: 空闲连接超时时间,默认值600000(10分钟),大于等于max-lifetime且max-lifetime>0,会被重置为0;不等于0且小于10秒,会被重置为10秒。 spring.datasource.hikari.max-lifetime: 连接最大存活时间,不等于0且小于30秒,会被重置为默认值30分钟.设置应该比mysql设置的超时时间短 spring.datasource.hikari.connection-timeout: 连接超时时间:毫秒,小于250毫秒,否则被重置为默认值30秒 spring.datasource.hikari.connection-test-query: 用于测试连接是否可用的查询语句 更多完整配置项可查看下表: name 描述 构造器默认值 默认配置validate之后的值 validate重置 autoCommit 自动提交从池中返回的连接 TRUE TRUE – connectionTimeout 等待来自池的连接的最大毫秒数 SECONDS.toMillis(30) = 30000 30000 如果小于250毫秒,则被重置回30秒 idleTimeout 连接允许在池中闲置的最长时间 MINUTES.toMillis(10) = 600000 600000 如果idleTimeout+1秒>maxLifetime 且 maxLifetime>0,则会被重置为0(代表永远不会退出);如果idleTimeout!=0且小于10秒,则会被重置为10秒 maxLifetime 池中连接最长生命周期 MINUTES.toMillis(30) = 1800000 1800000 如果不等于0且小于30秒则会被重置回30分钟 connectionTestQuery 如果您的驱动程序支持JDBC4,我们强烈建议您不要设置此属性 null null – minimumIdle 池中维护的最小空闲连接数 -1 10 minIdle<0或者minIdle>maxPoolSize,则被重置为maxPoolSize maximumPoolSize 池中最大连接数,包括闲置和使用中的连接 -1 10 如果maxPoolSize小于1,则会被重置。当minIdle<=0被重置为DEFAULT_POOL_SIZE则为10;如果minIdle>0则重置为minIdle的值 metricRegistry 该属性允许您指定一个 Codahale / Dropwizard MetricRegistry 的实例,供池使用以记录各种指标 null null – healthCheckRegistry 该属性允许您指定池使用的Codahale / Dropwizard HealthCheckRegistry的实例来报告当前健康信息 null null – poolName 连接池的用户定义名称,主要出现在日志记录和JMX管理控制台中以识别池和池配置 null HikariPool-1 – initializationFailTimeout 如果池无法成功初始化连接,则此属性控制池是否将 fail fast 1 1 – isolateInternalQueries 是否在其自己的事务中隔离内部池查询,例如连接活动测试 FALSE FALSE – allowPoolSuspension 控制池是否可以通过JMX暂停和恢复 FALSE FALSE – readOnly 从池中获取的连接是否默认处于只读模式 FALSE FALSE – registerMbeans 是否注册JMX管理Bean(MBeans) FALSE FALSE – catalog 为支持 catalog 概念的数据库设置默认 catalog driver default null – connectionInitSql 该属性设置一个SQL语句,在将每个新连接创建后,将其添加到池中之前执行该语句。 null null – driverClassName HikariCP将尝试通过仅基于jdbcUrl的DriverManager解析驱动程序,但对于一些较旧的驱动程序,还必须指定driverClassName null null – transactionIsolation 控制从池返回的连接的默认事务隔离级别 null null – validationTimeout 连接将被测试活动的最大时间量 SECONDS.toMillis(5) = 5000 5000 如果小于250毫秒,则会被重置回5秒 leakDetectionThreshold 记录消息之前连接可能离开池的时间量,表示可能的连接泄漏 0 0 如果大于0且不是单元测试,则进一步判断:(leakDetectionThreshold < SECONDS.toMillis(2) or (leakDetectionThreshold > maxLifetime && maxLifetime > 0),会被重置为0 . 即如果要生效则必须>0,而且不能小于2秒,而且当maxLifetime > 0时不能大于maxLifetime dataSource 这个属性允许你直接设置数据源的实例被池包装,而不是让HikariCP通过反射来构造它 null null – schema 该属性为支持模式概念的数据库设置默认模式 driver default null – threadFactory 此属性允许您设置将用于创建池使用的所有线程的java.util.concurrent.ThreadFactory的实例。 null null – scheduledExecutor 此属性允许您设置将用于各种内部计划任务的java.util.concurrent.ScheduledExecutorService实例 null null – 代码示例 本文的相关例子可以查看下面仓库中的chapter3-2目录: Github:https://github.com/dyc87112/SpringBoot-Learning/ Gitee:https://gitee.com/didispace/SpringBoot-Learning/ 如果您觉得本文不错,欢迎Star支持,您的关注是我坚持的动力! 参考资料 百度百科:JDBC HikariCP官方文档 Spring Boot默认HikariDataSource配置 欢迎关注我的公众号:程序猿DD,获得独家整理的学习资源和日常干货推送。如果您对我的专题内容感兴趣,也可以关注我的博客:didispace.com

优秀的个人博客,低调大师

MySQL基础篇(03):系统和自定义函数总结,触发器使用详解

本文源码:GitHub·点这里 || GitEE·点这里 一、系统封装函数 MySQL 有很多内置的函数,可以快速解决开发中的一些业务需求,大概包括流程控制函数,数值型函数、字符串型函数、日期时间函数、聚合函数等。以下列出了这些分类中常用的函数。 1、控制流程函数 case...when 根据值判断返回值,类比编程中的IF-ELSE判断。 -- DEMO 01 SELECT CASE DATE_FORMAT(NOW(),'%Y-%m-%d') WHEN '2019-12-29' THEN 'today' WHEN '2019-12-28' THEN 'yesterday' WHEN '2019-12-30' THEN 'tommor' ELSE 'Unknow' END; -- DEMO 02 SELECT (CASE WHEN 1>0 THEN 'true' ELSE 'false' END) AS result; if(expr1,expr2,expr3) 如果表达式 expr1 是TRUE,则 IF()的返回值为expr2; 否则返回值则为 expr3。 SELECT IF(1>2,'1>2','1<2') AS result ; SELECT IF(1<2,'yes ','no') AS result ; SELECT IF(STRCMP('test','test'),'no','yes'); ifnull(expr1,expr2) 如果表达式 expr1不为NULL,则返回值为expr1;否则返回值为 expr2。 SELECT IFNULL(NULL,'cicada'); SELECT IFNULL(1/1,'no'); 2、常用字符串函数 CHAR_LENGTH() 返回值为字符串的长度 。 SELECT CHAR_LENGTH(' c i c ') ;-- 包含空格 SELECT LENGTH(' S q l ') ; CONCAT(str1...) 拼接串联字符串。 SELECT CONCAT('My', 'S', 'ql'); SELECT CONCAT('My', NULL, 'QL'); -- 包含Null 则返回Null SELECT CONCAT("%", "Java", "%"); -- mybatis中拼接模糊查询 ELT(N,str1,str2,...) 若N = 1,则返回值为 str1 ,若N = 2,则返回值为 str2 ,以此类推,可以用来转换返回页面的状态。 SELECT ELT(1,'提交','审核中','规则通过') ; SELECT ELT(2,'提交','审核中','规则通过') ; FORMAT(X,D) 格式化数字类型。 SELECT FORMAT(3.1455,2) ; -- 四舍五入保留两位 SELECT TRUNCATE(3.1455,2) ; -- 直接截取两位 TRIM(str) 清空字符串空格。 SELECT LTRIM(' hel l o ') ;-- 清空左边 SELECT RTRIM(' hel l o ') ;-- 清空右边 SELECT TRIM(' hel l o ') ; -- 清空两边 SELECT REPLACE('M y S Q L',' ','') ; -- 替换掉全部空格 3、数值函数 FLOOR(X) 返回不大于X的最大整数值 。 SELECT FLOOR(1.23); -- 1 SELECT FLOOR(-1.23); -- -2 MOD(N,M) 模操作。返回N 被 M除后的余数。 SELECT MOD(29,9); -- 2 SELECT 29 MOD 9; -- 2 RAND() RAND(N) 返回一个随机浮点值,范围在0到1之间。若已指定一个整数参数 N ,则它被用作种子值,用来产生重复序列。 SELECT RAND(); -- 0.923 SELECT RAND(20) = RAND(20) ; -- TRUE 4、时间日期函数 ADDDATE(date,INTERVAL expr type) 给指定日期,以指定类型进行运算。 SELECT DATE_ADD('2019-12-29', INTERVAL 3 DAY); -- 2020-01-01 CURDATE() 将当前日期按照'YYYY-MM-DD' 或YYYYMMDD 格式的值返回,具体格式根据函数用在字符串或是数字语境中而定。 SELECT CURDATE(); -- '2019-12-29' 字符串 SELECT CURDATE() + 0; -- 20180725 数字 DATE(expr) 提取日期或时间日期表达式expr中的日期部分。 SELECT DATE('2019-12-31 01:02:03'); -- '2019-12-31' SELECT DATE('2019-12-31 01:02:03')+0; -- 20191231 DATE_FORMAT(date,format) 根据format 字符串进行 date 值的格式化。 SELECT DATE_FORMAT(NOW(), '%Y-%m-%d'); -- 2019-12-29 SELECT DATE_FORMAT(NOW(), '%Y年%m月%d日'); -- 2019年12月29日 5、聚合函数 AVG([distinct] expr) 求平均值 COUNT({*|[distinct] } expr) 统计行的数量 MAX([distinct] expr) 求最大值 MIN([distinct] expr) 求最小值 SUM([distinct] expr) 求累加和 二、自定义函数 1、概念简介 函数存储着一系列sql语句,调用函数就是一次性执行这些语句。所以函数可以降低语句重复。函数注重返回值,而触发器注重执行过程,所以一些语句无法执行。所以函数并不是单纯的sql语句集合。 2、使用方式 create function 函数名([参数列表]) returns 数据类型 begin sql语句; return 值; end; 参数列表的格式是: 变量名 数据类型。 无参案例 CREATE FUNCTION mysum1 () RETURNS INT RETURN (2+3)*2; SELECT mysum1 () ; 有参函数 表结构 CREATE TABLE t01_user ( id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', user_name varchar(20) DEFAULT NULL COMMENT '用户名称' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '用户表'; 函数用法 create function get_name(p_id INT) returns VARCHAR(20) begin declare userName varchar(20); select user_name from t01_user where id=p_id into userName; return userName; end; SELECT get_name(1) ; 3、函数查看 show create function get_name ; 4、删除函数 drop function get_name ; 5、函数注意事项 函数是事先经过编译,才能在服务器环境调用,所以MySQL集群环境需要同步编译;MySQL是多线程环境,所以要保证函数也是线程安全 。 三、触发器 1、触发器简介 触发器是特殊的存储过程,不同的是存储过程要用CALL来调用,而触发器不需要使用CALL。也不需要手工启动,只要当一个预定义的事件发生的时候,就会被MYSQL自动触发调用。 2、创建触发器 触发器语法 CREATE TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR EACH ROW trigger_stmt trigger_name:触发器命名 ; trigger_time: 触发动作的时间 ; trigger_event: 激活触发器的语句类型 ; tbl_name: 触发器作用的表明,非临时表 ; trigger_stmt:触发程序执行的语句 ; 表数据同步 当向用户表 t01_user 写入数据时,同时向 t02_back 表写入一份备份数据。 -- 用户备份表 CREATE TABLE t02_back ( id int(11) NOT NULL PRIMARY KEY COMMENT '主键ID', user_name varchar(20) DEFAULT NULL COMMENT '用户名称' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '用户备份'; -- 触发器程序 DROP TRIGGER IF EXISTS user_back_trigger ; CREATE TRIGGER user_back_trigger AFTER INSERT ON t01_user FOR EACH ROW BEGIN INSERT INTO t02_back (id,user_name) VALUES (new.id,new.user_name); END ; -- 测试案例 INSERT INTO t01_user (user_name) VALUES ('smile'),('mysql') ; SELECT * FROM t02_back ; 3、查看触发器 查看触发器是指数据库中已存在的触发器的定义、状态、语法信息等。可以在TRIGGERS表中查看触发器信息。 SELECT * FROM `information_schema`.`TRIGGERS` WHERE `TRIGGER_NAME`='user_back_trigger'; 4、删除触发器 DROP TRIGGER语句可以删除MYSQL中已经定义的触发器,删除触发器的基本语法。 DROP TRIGGER [schema_name.]trigger_name 5、触发器注意事项 触发事件 对于相同的表,相同的事件只能创建一个触发器,比如对表t01_user创建两次AFTER INSERT触发器,就会报错。 执行效率 触发器可以减少应用端和数据库的通信次数和业务逻辑,但是基于行触发的逻辑,如果数据集非常大,效率会降低。 事务问题 触发器执行和原表的执行语句是否在同一个事务中,取决于触发表的存储引擎是否支持事务。 四、源代码地址 GitHub·地址 https://github.com/cicadasmile/mysql-data-base GitEE·地址 https://gitee.com/cicadasmile/mysql-data-base

优秀的个人博客,低调大师

JavaEE基础(06):Servlet整合C3P0数据库连接池

本文源码:GitHub·点这里 || GitEE·点这里 一、C3P0连接池 1、C3P0简介 C3P0是一个开源的JDBC连接池,应用程序根据C3P0配置来初始化数据库连接,可以自动回收空闲连接的功能。 2、核心依赖 <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>${c3p0.version}</version> </dependency> 3、配置文件 配置文件位置:放在resources目录下,这样C3P0组件会自动加载该配置。 <?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <default-config> <!-- 核心参数配置 --> <property name="jdbcUrl">jdbc:mysql://localhost:3306/servlet-jdbc</property> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="user">root</property> <property name="password">123</property> <!-- 池参数配置 --> <property name="acquireIncrement">3</property> <property name="initialPoolSize">10</property> <property name="minPoolSize">2</property> <property name="maxPoolSize">10</property> </default-config> </c3p0-config> 4、编写工具类 该工具类用来获取数据库连接,和释放相关连接。 public class C3P0Pool { private static DataSource dataSource = new ComboPooledDataSource(); public static DataSource getDataSource() { return dataSource ; } /** * 获取连接 */ public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } /** * 释放连接 */ public static void close(ResultSet resultSet, PreparedStatement pst, Connection connection) { if (resultSet != null) { try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } } if (pst != null) { try { pst.close(); } catch (SQLException e) { e.printStackTrace(); } } if (connection != null) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } } 二、数据操作封装 1、新增数据 public class UserJdbcInsert { public static void insertUser (UserInfo userInfo){ try { Connection connection = C3P0Pool.getConnection(); String sql = "INSERT INTO user_info (user_name,user_age) VALUES (?,?)" ; PreparedStatement statement = connection.prepareStatement(sql); statement.setString(1,userInfo.getUserName()); statement.setString(2,userInfo.getUserAge().toString()); statement.execute() ; C3P0Pool.close(null, statement, connection); } catch (Exception e) { e.printStackTrace(); } } public static void batchInsertUser (List<UserInfo> userInfoList){ try { Connection connection = C3P0Pool.getConnection(); String sql = "INSERT INTO user_info (user_name,user_age) VALUES (?,?)" ; PreparedStatement statement = connection.prepareStatement(sql); for (UserInfo userInfo:userInfoList){ statement.setString(1,userInfo.getUserName()); statement.setString(2,userInfo.getUserAge().toString()); statement.addBatch(); } statement.executeBatch() ; C3P0Pool.close(null, statement, connection); } catch (Exception e) { e.printStackTrace(); } } } 2、查询数据 public class UserJdbcQuery { public static UserInfo queryUser (String userName){ UserInfo userInfo = null ; try { Connection connection = C3P0Pool.getConnection(); String sql = "SELECT * FROM user_info WHERE user_name=?" ; PreparedStatement statement = connection.prepareStatement(sql); statement.setString(1,userName); ResultSet resultSet = statement.executeQuery() ; while (resultSet.next()){ int id = resultSet.getInt("id"); String name = resultSet.getString("user_name"); int age = resultSet.getInt("user_age"); System.out.println("ID:"+id+";name:"+name+";age:"+age); userInfo = new UserInfo(name,age) ; } C3P0Pool.close(resultSet, statement, connection); } catch (Exception e) { e.printStackTrace(); } return userInfo ; } } 3、更新数据 public class UserJdbcUpdate { public static void updateUser (String name,Integer age,Integer id){ try { Connection connection = C3P0Pool.getConnection(); String sql = "UPDATE user_info SET user_name=?,user_age=? WHERE id=?" ; PreparedStatement statement = connection.prepareStatement(sql); statement.setString(1,name); statement.setInt(2,age); statement.setInt(3,id); statement.executeUpdate() ; C3P0Pool.close(null, statement, connection); } catch (Exception e) { e.printStackTrace(); } } } 4、删除数据 public class UserJdbcDelete { public static void deleteUser (Integer id){ try { Connection connection = C3P0Pool.getConnection(); String sql = "DELETE FROM user_info WHERE id=?" ; PreparedStatement statement = connection.prepareStatement(sql); statement.setInt(1,id); statement.executeUpdate() ; C3P0Pool.close(null, statement, connection); } catch (Exception e) { e.printStackTrace(); } } } 三、Servlet接口 public class JdbcServletImpl extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String userName = request.getParameter("userName") ; UserInfo userInfo = UserJdbcQuery.queryUser(userName) ; response.setContentType("text/html;charset=utf-8"); response.getWriter().print("用户信息:"+userInfo); } } 测试访问: http://localhost:6003/jdbcServletImpl?userName=LiSi 页面打印: 用户信息:UserInfo{userName='LiSi', userAge=22}

资源下载

更多资源
Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册