1. Druid是什么? Druid是Java语言中最好的数据库连接池。Druid能够提供强大的监控和扩展功能。 2. 在哪里下载druid 正式版本下载: maven中央仓库: http://central.maven.org/maven2/com/alibaba/druid/ 3. 怎么获取Druid的源码 Druid是一个开源项目,源码托管在github上,源代码仓库地址是 https://github.com/alibaba/druid。同时每次Druid发布正式版本和快照的时候,都会把源码打包,你可以从上面的下载地址中找到相关版本的源码 4. 怎么配置maven Druid 0.1.18 之后版本都发布到maven中央仓库中,所以你只需要在项目的pom.xml中加上dependency就可以了。例如:
|
1 2 3 4 5 |
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid-version}</version> </dependency> |
也可以选择 Maven仓库查找公共的仓库地址:http://www.mvnrepository.com/artifact/com.alibaba/druid 5. 怎么打开Druid的监控统计功能 Druid的监控统计功能是通过filter-chain扩展实现,如果你要打开监控统计功能,配置StatFilter,具体看这里:https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatFilter 6. 怎样使用Druid的内置监控页面 内置监控页面是一个Servlet,具体配置看这里:https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatViewServlet%E9%85%8D%E7%BD%AE 7. 内置监控中的Web和Spring关联监控怎么配置? Web关联监控配置 https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_%E9%85%8D%E7%BD%AEWebStatFilter Spring关联监控配置 https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_Druid%E5%92%8CSpring%E5%85%B3%E8%81%94%E7%9B%91%E6%8E%A7%E9%85%8D%E7%BD%AE 8. 怎么配置防御SQL注入攻击 Druid提供了WallFilter,它是基于SQL语义分析来实现防御SQL注入攻击的。具体配置看这里:https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE-wallfilter 9. Druid有没有参考配置 不同的业务场景需求不同,你可以使用我们的参考配置,但建议你仔细阅读相关文档,了解清楚之后做定制配置。https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_DruidDataSource%E5%8F%82%E8%80%83%E9%85%8D%E7%BD%AE 10. 我想日志记录JDBC执行的SQL,如何配置 Druid提供了Log4jFilter、CommonsLogFilter和Slf4jFilter,具体配置看这里https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_LogFilter 11. 我的程序可能产生连接泄漏了,有什么办法? Druid提供了多种监测连接泄漏的手段,具体看这里:https://github.com/alibaba/druid/wiki/%E8%BF%9E%E6%8E%A5%E6%B3%84%E6%BC%8F%E7%9B%91%E6%B5%8B 12. 在Druid中使用PSCache会有内存占用过大问题么? 连接Oracle数据库,打开PSCache,在其他的数据库连接池都会存在内存占用过多的问题,Druid是唯一解决这个问题的连接池。具体看这里:https://github.com/alibaba/druid/wiki/Oracle%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%8BPreparedStatementCache%E5%86%85%E5%AD%98%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88 13. 有没有和其他数据库连接池的对比? 各种数据库连接池对比https://github.com/alibaba/druid/wiki/%E5%90%84%E7%A7%8D%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9E%E6%8E%A5%E6%B1%A0%E5%AF%B9%E6%AF%94 14. 从其他连接池迁移要注意什么? 不同连接池的参数参照对比: http://code.alibabatech.com/wiki/pages/viewpage.action?pageId=6947005 DBCP迁移 https://github.com/alibaba/druid/wiki/DBCP%E8%BF%81%E7%A7%BB 15. Druid中有没有类似Jboss DataSource中的ExceptionSorter ExceptionSorter是JBoss DataSource中的优秀特性,Druid也有一样功能的ExceptionSorter,但不用手动配置,自动识别生效的。具体看这里:https://github.com/alibaba/druid/wiki/ExceptionSorter_cn 16. Druid中的maxIdle为什么是没用的? maxIdle是Druid为了方便DBCP用户迁移而增加的,maxIdle是一个混乱的概念。连接池只应该有maxPoolSize和minPoolSize,druid只保留了maxActive和minIdle,分别相当于maxPoolSize和minPoolSize。 17. 我的应用配置的是JNDI数据源,可以用DruidDataSource么? DruidDataSource支持JNDI配置,具体看这里:https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_JNDI_Tomcat 具体实现的类是这个:com.alibaba.druid.pool.DruidDataSourceFactory,你可以阅读代码加深理解。 18. 我的应用已使用DBCP,是代码中写死的,怎样更换为Druid? 可以的,Druid提供了一个中完全平滑迁移DBCP的办法。 1) 从http://repo1.maven.org/maven2/com/alibaba/druid/druid-wrapper/ 下载druid-wrapper-xxx.jar 2) 加入druid-xxx.jar 3) 从你的WEB-INF/lib/中删除dbcp-xxx.jar 4) 按需要加上配置,比如JVM启动参数加上-Ddruid.filters=stat,动态配置druid的filters […]
View Detailsthymeleaf的模板默认路径是resources的templates,我想把模板放到webapp下,然后就弄了半天,最后终于发现问题了(想饿自己三天不吃饭~),记录一下这次惨痛的教训😂 springboot使用thymeleaf在pom文件中引包,然后修改项目结构,修改yml配置就ok了 pom文件中引包 org.springframework.boot spring-boot-starter-thymeleaf 修改项目结构 最后点击ok然后去设置yml文件 from:https://blog.csdn.net/zhaocongc/article/details/87183872
View Details首先堆栈和堆(托管堆)都在进程的虚拟内存中。(在32位处理器上每个进程的虚拟内存为4GB) 堆栈stack 堆栈中存储值类型。 堆栈实际上是向下填充,即由高内存地址指向低内存地址填充。 堆栈的工作方式是先分配内存的变量后释放(先进后出原则)。 堆栈中的变量是从下向上释放,这样就保证了堆栈中先进后出的规则不与变量的生命周期起冲突! 堆栈的性能非常高,但是对于所有的变量来说还不太灵活,而且变量的生命周期必须嵌套。 通常我们希望使用一种方法分配内存来存储数据,并且方法退出后很长一段时间内数据仍然可以使用。此时就要用到堆(托管堆)! 堆(托管堆)heap 堆(托管堆)存储引用类型。 此堆非彼堆,.NET中的堆由垃圾收集器自动管理。 与堆栈不同,堆是从下往上分配,所以自由的空间都在已用空间的上面。 比如创建一个对象: Customer cus; cus = new Customer(); 申明一个Customer的引用cus,在堆栈上给这个引用分配存储空间。这仅仅只是一个引用,不是实际的Customer对象! cus占4个字节的空间,包含了存储Customer的引用地址。 接着分配堆上的内存以存储Customer对象的实例,假定Customer对象的实例是32字节,为了在堆上找到一个存储Customer对象的存储位置。 .NET运行库在堆中搜索第一个从未使用的,32字节的连续块存储Customer对象的实例! 然后把分配给Customer对象实例的地址赋给cus变量! 从这个例子中可以看出,建立对象引用的过程比建立值变量的过程复杂,且不能避免性能的降低! 实际上就是.NET运行库保存对的状态信息,在堆中添加新数据时,堆栈中的引用变量也要更新。性能上损失很多! 有种机制在分配变量内存的时候,不会受到堆栈的限制:把一个引用变量的值赋给一个相同类型的变量,那么这两个变量就引用同一个堆中的对象。 当一个应用变量出作用域时,它会从堆栈中删除。但引用对象的数据仍然保留在堆中,一直到程序结束 或者 该数据不被任何变量应用时,垃圾收集器会删除它。 装箱转化 using System; class Boxing { public static void Main() { int i=110; object obj=i; i=220; Console.WriteLine("i={0},obj={1}",i,obj); obj=330; Console.WriteLine("i={0},obj={1}",i,obj); } } 定义整数类型变量I的时候,这个变量占用的内存是内存栈中分配的,第二句是装箱操作将变量 110存放到了内存堆中,而定义object对象类型的变量obj则在内存栈中,并指向int类型的数值110,而该数值是付给变量i的数值副本。 所以运行结果是 i=220,obj=110 i=220,obj=330 内存格局通常分为四个区 全局数据区:存放全局变量,静态数据,常量 代码区:存放所有的程序代码 栈区:存放为运行而分配的局部变量,参数,返回数据,返回地址等, 堆区:即自由存储区 值类型变量与引用类型变量的内存分配模型也不一样。为了理解清楚这个问题,读者首 先必须区分两种不同类型的内存区域:线程堆栈(Thread Stack)和托管堆(Managed Heap)。 每个正在运行的程序都对应着一个进程(process),在一个进程内部,可以有一个或多 个线程(thread),每个线程都拥有一块“自留地”,称为“线程堆栈”,大小为1M,用于保 存自身的一些数据,比如函数中定义的局部变量、函数调用时传送的参数值等,这部分内存 区域的分配与回收不需要程序员干涉。 所有值类型的变量都是在线程堆栈中分配的。 另一块内存区域称为“堆(heap)”,在.NET 这种托管环境下,堆由CLR 进行管理,所 以又称为“托管堆(managed heap)”。 用new 关键字创建的类的对象时,分配给对象的内存单元就位于托管堆中。 在程序中我们可以随意地使用new 关键字创建多个对象,因此,托管堆中的内存资源 是可以动态申请并使用的,当然用完了必须归还。 打个比方更易理解:托管堆相当于一个旅馆,其中的房间相当于托管堆中所拥有的内存 单元。当程序员用new 方法创建对象时,相当于游客向旅馆预订房间,旅馆管理员会先看 一下有没有合适的空房间,有的话,就可以将此房间提供给游客住宿。当游客旅途结束,要 办理退房手续,房间又可以为其他旅客提供服务了。 […]
View Details解决方案 今天像往常一样,编写文章,并使用gulp bulid压缩代码,但是一运行:gulp build 就出现了这个错误:AssertionError: Task function must be specified。 gulp项目需要全局安装gulp和项目内安装gulp,通过 gulp -v 查看全局gulp 和本地项目的gulp版本: image.png 这俩显然,不一致。 下面,我们可以看到项目里记录的gulp的版本号: image.png 可以卸载修改json文件里面的版本号:为gulp 3 版本。如 3.9.1 重新运行 npm install gulp 3 和 gulp 4运行方式是不一样的,所以会出现错误。具体细节,可以看这里 gup3 VS gulp4 区别 Gulp 4最大的变化就是你不能像以前那样传递一个依赖任务列表。 Gulp3,如果有一个任务A,B和C的列表,你想在一个序列中运行(确保A在B开始之前完成,而B在C开始之前完成),代码如下:
|
1 2 3 4 5 6 7 8 9 |
gulp.task('a', function () { // Do something. }); gulp.task('b', ['a'], function () { // Do some stuff. }); gulp.task('c', ['b'], function () { // Do some more stuff. }); |
在Gulp 4中,你不能再这样做了。你会得到以下错误:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
assert.js:85 throw new assert.AssertionError({ ^ AssertionError: Task function must be specified at Gulp.set [as _setTask] (/home/hope/web/node_modules/undertaker/lib/set-task.js:10:3) at Gulp.task (/home/hope/web/node_modules/undertaker/lib/task.js:13:8) at Object.<anonymous> (/home/hope/web/gulpfile.js:31:6) at Module._compile (module.js:570:32) at Object.Module._extensions..js (module.js:579:10) at Module.load (module.js:487:32) at tryModuleLoad (module.js:446:12) at Function.Module._load (module.js:438:3) at Module.require (module.js:497:17) at require (internal/module.js:20:19) |
不要用Gulp3的方式指定依赖任务,你需要使用gulp.series和gulp.parallel,因为gulp任务现在只有两个参数。 gulp.series:按照顺序执行 gulp.paralle:可以并行计算
|
1 2 3 |
gulp.task('my-tasks', gulp.series('a', 'b', 'c', function() { // Do something after a, b, and c are finished. })); |
|
1 2 3 |
gulp.task('build', gulp.parallel('styles', 'scripts', 'images', function () { // Build the website. })); |
或者这样
|
1 2 3 |
gulp.task('my-tasks', gulp.series('a', gulp.parallel('styles','scripts', 'images'), 'b', 'c', function() { // Do something after a, b, and c are finished. })); |
相关任务必须在被调用之前发生。 参考: https://github.com/gulpjs/gulp/blob/master/docs/API.md https://www.fastless.com/gulp-4 https://www.jianshu.com/p/40b99bed3127 作者:cuteximi_1995 链接:https://www.jianshu.com/p/c30ff8592421 来源:简书 简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
View Detailsvs code格式化代码的快捷键如下:(来源于这里) On Windows Shift + Alt + F On Mac Shift + Option + F On Ubuntu Ctrl + Shift + I 但是自带的格式化并不能满足我的需求,这个时候,不得不说插件大法好。 1、代码格式化为eslint风格(参考自这里) 需要插件:eslint 在设置中添加: "eslint.autoFixOnSave": true, "eslint.validate": [ "javascript", "javascriptreact", { "language": "html", "autoFix": true }, { "language": "vue", "autoFix": true } ], eslint.autoFixOnSave 用来进行保存时自动格式化,但是默认只支持 javascript .js 文件。 eslint.validate 用来配置作用的文件类型。 然后在保存代码的时候,就会自动格式化为eslint风格(需要保存多次)。 2、HTML格式化代码缩进 需要插件:Vetur Vetur是一个功能非常强大的插件,为 vs code 编写Vue代码提供了强大的支持,也支持大多数主流的前端开发脚本。具体可以看这里->Vetur文档 安装这个插件后,可以在设置中看到如下的内容: 为了让HTML代码可以格式化缩进,添加如下一条:
|
1 |
<span class="hljs-string">"vetur.format.defaultFormatter.html"</span>: <span class="hljs-string">"prettier"</span> |
然后用格式化代码的快捷键就可以了。 from:https://blog.csdn.net/latency_cheng/article/details/80409202
View Detailsgulpfile.js
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
var gulp = require('gulp'); var webserver = require('gulp-webserver'); gulp.task('webserver', function () { gulp.src('./') .pipe(webserver({ host: 'localhost', port: 3000, livereload: true, open: './pages/myPages/login.html', directoryListing: { enable: true, path: './' }, proxies: [ { source: '/api', target: 'http://jsonplaceholder.typicode.com' } ] })) }); gulp.task('default', ['webserver'], function () { console.log('成功'); }); |
1、在本地起一个服务,端口号为3000。 2、open:默认打开的文件的路径 3、directoryListing:是否显示文件列表 4、proxies: 设置代理 接口调用: 接口调用 url http://localhost:3000/api 作者:动次动次forever 链接:https://www.jianshu.com/p/237bc5c04fa1 来源:简书 简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
View Details为什么需要使用代理? 目前,前端发展飞速,前后端分离式开发已经不是新鲜事儿。 1 如果前端只是静态的页面(不需要调用后端的api加载动态数据),那么前端直接在本地开发即可。 即使是前后端分开部署,只需要单独为前端启动一个服务,使用gulp-connect即可。不会?(请戳gulp之用gulp-connect开启一个本地webServer) 2 如果前端需要调用后端提供的接口呢?除非前后端部署在同一个服务器上,否则由于浏览器的限制是没办法跨域请求数据的。真实情况是,我们在本地开发时就需要访问接口,这时后端的程序猿给你的往往是这样一个地址 http://192.168.1.123/controller/action,有人说上传代码到http://192.168.1.123/放在一个目录下不就行了,是啊!可以的。但是好麻烦有没有,调试接口需要传代码上去!!!! 3 如果我的数据是从其他的服务器来的呢?例如我想访问豆瓣的开放接口
|
1 2 3 4 |
$.post(<span class="hljs-string">'https://api.douban.com/v2/book/1220562'</span>,{},<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">data</span>)</span>{ <span class="hljs-built_in">console</span>.log(data); }) |
豆瓣告诉你,不行!你跨域了! 所以,还是代理来的方便。 代理是个什么鬼? 代理请求通俗点讲,就是把发往 a.com的请求,通过代理服务器发送到b.com。 怎么开启一个代理? 代码如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<span class="hljs-comment">//服务端口</span> <span class="hljs-keyword">const</span> PORT=<span class="hljs-number">8000</span>; <span class="hljs-comment">//启动服务的根目录</span> <span class="hljs-keyword">const</span> server_root=<span class="hljs-string">'src'</span> <span class="hljs-comment">//引用gulp</span> <span class="hljs-keyword">var</span> gulp = <span class="hljs-built_in">require</span>(<span class="hljs-string">'gulp'</span>); <span class="hljs-comment">//引用gulp开启服务的插件</span> <span class="hljs-keyword">var</span> connect = <span class="hljs-built_in">require</span>(<span class="hljs-string">'gulp-connect'</span>); <span class="hljs-comment">//引用插件 gulp代理中间件插件</span> <span class="hljs-keyword">var</span> proxy = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http-proxy-middleware'</span>); <span class="hljs-comment">//开启服务</span> gulp.task(<span class="hljs-string">'proxyServer'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>() </span>{ connect.server({ <span class="hljs-attr">root</span>: [server_root], <span class="hljs-attr">port</span>: PORT, <span class="hljs-attr">middleware</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">connect, opt</span>) </span>{ <span class="hljs-keyword">return</span> [ proxy(<span class="hljs-string">'/api'</span>, { <span class="hljs-attr">target</span>: <span class="hljs-string">'https://api.douban.com/v2'</span>,<span class="hljs-comment">//代理的目标地址</span> changeOrigin:<span class="hljs-literal">true</span>,<span class="hljs-comment">//</span> pathRewrite:{<span class="hljs-comment">//路径重写规则 </span> <span class="hljs-string">'^/api'</span>:<span class="hljs-string">''</span> } }) ] } }); }); |
说明 '/api' =>匹配你要代理的请求地址前缀 target=》你要把请求代理到哪 pathRewrite =》是把你再页面中写的请求地址 某部分 重写为后面的字符串 (例子中讲 请求中写的 /api 重写为 空字符串) 也就是发往 /api/book/1220562的请求最终会被发往 https://api.douban.com/v2/book/1220562 页面写请求时的写法
|
1 2 3 4 |
$.post(<span class="hljs-string">'/api/book/1220562'</span>,{},<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">data</span>)</span>{ <span class="hljs-built_in">console</span>.log(data); }) |
目录结构 image.png 运行效果 image.png 结语 当然还有其他的方式,比如 node、cros、jsonp、phpheader、nginx设置代理 作者:coder_turbo 链接:https://www.jianshu.com/p/cc543fd0d7c5 来源:简书 简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
View Details由于我们的接口是通过springboot一键式打包成jar包发布到服务器的,因此在通过接口上传文件之后,客户端如果还需要再访问该文件,那就需要用到静态资源访问,spring配置如下:
|
1 2 3 |
spring: resources: static-locations: file:E:\workspace\serverWorkspace\upload\images\photo\20180820,file:/opt/www |
一个是widows下做测试使用,另一个是linux下测试服务器使用。 有时候你会发现可能配置了static-locations但无效,原因可能就是你的目录不对,请仔细检查一下,别问我怎么知道的 如此之后验证即可,如我的: 浏览器输入: localhost:9999/filename ——————— 作者:weixin_34387284 来源:CSDN 原文:https://blog.csdn.net/weixin_34387284/article/details/87066649 版权声明:本文为博主原创文章,转载请附上博文链接!
View Details|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<insert id="saveOrUpdate" > <selectKey keyProperty="count" resultType="int" order="BEFORE"> select count(*) from country where id = #{id} </selectKey> <if test="count > 0"> update country set countryname = #{countryname},countrycode = #{countrycode} where id = #{id} </if> <if test="count==0"> insert into country values(#{id},#{countryname},#{countrycode}) </if> </insert> |
注意如果insert的parameterType是自定义对象的话,对象里需要有count属性,否则会报count属性找不到的错误 from:https://ydlmlh.iteye.com/blog/2236671
View Details在这篇文章里面主要讲解如何在mybatis里面使用一对一、一对多、多表联合查询(类似视图)操作的例子。 注:阅读本文前请先大概看一下之前两篇文章。 一、表结构 班级表class,学生表student,班级学生关系表ClassStudent。 这里一个学生只会在一个班级里面,也就是一对一的关系;一个班级有多个学生,也就是一对多的关系。 结构如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
CREATE TABLE [dbo].[Class]( [class_id] [int] NOT NULL, [class_name] [varchar](50) NOT NULL, CONSTRAINT [PK_Class] PRIMARY KEY CLUSTERED ( [class_id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] CREATE TABLE [dbo].[ClassStudent]( [class_id] [int] NOT NULL, [student_id] [int] NOT NULL ) ON [PRIMARY] CREATE TABLE [dbo].[Student]( [s_id] [int] NOT NULL, [s_name] [varchar](50) NOT NULL, CONSTRAINT [PK_Student] PRIMARY KEY CLUSTERED ( [s_id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] |
3张表的数据如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
insert into Class values(1,'三(1)班') insert into Class values(2,'三(2)班') insert into Class values(3,'三(3)班') insert into Class values(4,'三(4)班') insert into Student values(1001,'张三') insert into Student values(1002,'李四') insert into Student values(1003,'赵五') insert into Student values(1004,'王二麻子') insert into ClassStudent values(1,1001) insert into ClassStudent values(1,1003) insert into ClassStudent values(4,1002) insert into ClassStudent values(3,1004) |
二、在原项目下新建一个包com.mybatis.sqljoinrelation,在包里面新建一个sqlMapper.xml的映射文件,在项目的mybatis的配置文件conf.xml中对这个sqlMapper.xml进行注册,注册片段如下:
|
1 2 3 4 |
<!-- 注册映射文件 --> <mappers> <mapper resource="com/mybatis/sqljoinrelation/sqlMapper.xml" /> </mappers> |
紧接着在原项目下再新建一个包com.mybatis.bean,在里面新建实体类 学生:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
package com.mybatis.bean; /** * 学生(临时) */ public class StudentTemp { private int studentid; private String studentname; private Class tempClass; public Class getTempClass() { return tempClass; } public void setTempClass(Class tempClass) { this.tempClass = tempClass; } public int getStudentid() { return studentid; } public void setStudentid(int studentid) { this.studentid = studentid; } public String getStudentname() { return studentname; } public void setStudentname(String studentname) { this.studentname = studentname; } @Override public String toString() { return "StudentTemp [studentid=" + studentid + ", studentname=" + studentname + ", tempClass=" + tempClass + "]"; } } |
班级:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package com.mybatis.bean; /** * 班级 */ public class Class { private int classid; private String classname; public int getClassid() { return classid; } public void setClassid(int classid) { this.classid = classid; } public String getClassname() { return classname; } public void setClassname(String classname) { this.classname = classname; } @Override public String toString() { return "Class [classid=" + classid + ", classname=" + classname + "]"; } } |
学生班级视图类:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
package com.mybatis.bean; public class studentclass { private int s_id; private String s_name; private int class_id; private String class_name; public int getS_id() { return s_id; } public void setS_id(int s_id) { this.s_id = s_id; } public String getS_name() { return s_name; } public void setS_name(String s_name) { this.s_name = s_name; } public int getClass_id() { return class_id; } public void setClass_id(int class_id) { this.class_id = class_id; } public String getClass_name() { return class_name; } public void setClass_name(String class_name) { this.class_name = class_name; } @Override public String toString() { return "studentclass [s_id=" + s_id + ", s_name=" + s_name + ", class_id=" + class_id + ", class_name=" + class_name + "]"; } } |
三、查询操作 1、 一对一,查询学生编号等于1001且他所在班级信息 2、一对多,查询班级编号等于1且包含所有学生信息 3、类似视图查询学生编号等于1001且他所在班级信息 sqlMapper.xml如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.mybatis.sqljoinrelation.sqlMapper"> <!-- 1、 获取某学生以及该学生所在班级的信息 --> <!-- 可以显示指出c.class_id,c.class_name,s.s_id,s.s_name列明, 如果用"*"代替,则mybatis会自动匹配resultMap中提供的列名 --> <select id="getStudentAndClass" parameterType="int" resultMap="studentClassMap"> select c.class_id,c.class_name,s.s_id,s.s_name from Class c left join ClassStudent cs on c.class_id = cs.class_id left join Student s on cs.student_id = s.s_id where s.s_id = #{id} </select> <!-- resultMap中的type表示返回什么类型的对象 --> <resultMap type="com.mybatis.bean.StudentTemp" id="studentClassMap"> <!-- property 表示com.mybatis.bean.StudentTemp中的属性; column 表示表中的列名 --> <id property="studentid" column="s_id" /> <result property="studentname" column="s_name" /> <!-- association字面意思关联,这里只专门做一对一关联; property表示是com.mybatis.bean.StudentTemp中的属性名称; javaType表示该属性是什么类型对象 --> <association property="tempClass" javaType="com.mybatis.bean.Class"> <!-- property 表示com.mybatis.bean.Class中的属性; column 表示表中的列名 --> <id property="classid" column="class_id" /> <result property="classname" column="class_name" /> </association> </resultMap> <!-- 2、获取某学生以及该学生所在班级的信息,类似视图实现方式 --> <!-- resultType 对应简单类型,也就是实体中的属性名称与数据库表字段名称一模一样; resultMap 对应复杂类型,属性名称与字段名称不一样可以通过resultMap中property,column进行映射 --> <select id="getStudentAndClassView" parameterType="int" resultType="com.mybatis.bean.studentclass"> select c.class_id,c.class_name,s.s_id,s.s_name from Class c left join ClassStudent cs on c.class_id = cs.class_id left join Student s on cs.student_id = s.s_id where s.s_id = #{id} </select> <!-- 3、获取某班级以及班级里面所有学生的信息 --> <select id="getClassStudents" parameterType="int" resultMap="classStudentsMap"> select * from Class c left join ClassStudent cs on c.class_id = cs.class_id left join Student s on cs.student_id = s.s_id where c.class_id = #{id} </select> <resultMap type="com.mybatis.bean.ClassTemp" id="classStudentsMap"> <id property="classid" column="class_id"/> <result property="classname" column="class_name"/> <!-- property表示集合类型属性名称,ofType表示集合中的对象是什么类型 --> <collection property="students" ofType="com.mybatis.bean.Student"> <id property="studentid" column="s_id"/> <result property="studentname" column="s_name"/> </collection> </resultMap> </mapper> |
测试代码如下: 一对一与类似视图查询的代码在一起,如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
package com.mybatis.sqljoinrelation; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import com.mybatis.util.MybatisUtils; /** * 一对一 */ public class testonetoone { public static void main(String[] args) { SqlSessionFactory factory = MybatisUtils.getFactory(); SqlSession session = null; try { session = factory.openSession(true); //1、StudentTemp String statement1 = "com.mybatis.sqljoinrelation.sqlMapper.getStudentAndClass"; System.out.println(session.selectOne(statement1, 1001)); //2、用model类型接收数据 String statement2 = "com.mybatis.sqljoinrelation.sqlMapper.getStudentAndClassView"; System.out.println(session.selectOne(statement2, 1001)); } catch (Exception e) { e.printStackTrace(); }finally{ session.close(); } } } |
一对多测试代码如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
package com.mybatis.sqljoinrelation; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import com.mybatis.util.MybatisUtils; /** * 一对多 */ public class testonetomany { public static void main(String[] args) { SqlSessionFactory factory = MybatisUtils.getFactory(); SqlSession session = null; try { session = factory.openSession(true); //1、StudentTemp String statement = "com.mybatis.sqljoinrelation.sqlMapper.getClassStudents"; System.out.println(session.selectOne(statement, 1)); } catch (Exception e) { e.printStackTrace(); }finally{ session.close(); } } } |
四、sqlMapper.xml需要说明的问题 1、一对一:<association property="tempClass" javaType="com.mybatis.bean.Class"> association字面意思关联,这里只专门做一对一关联; property表示是com.mybatis.bean.StudentTemp中的属性名称; javaType表示该属性是什么类型对象 2、类似视图查询: <select id="getStudentAndClassView" parameterType="int" resultType="com.mybatis.bean.studentclass"> resultType 对应简单类型,也就是实体中的属性名称与数据库表字段名称一模一样; resultMap 对应复杂类型,属性名称与字段名称不一样可以通过resultMap中property,column进行映射,其中一对一与一对多都是用resultMap来映射 3、一对多:<collection property="students" ofType="com.mybatis.bean.Student"> collection字面意思是集合,这里专门做一对多关联 ,property表示集合类型属性名称,ofType表示集合中的对象是什么类型 4、<select>select * from …</student>与<select>select 字段1,字段2,字段3… from …</student> 可以显示指出c.class_id,c.class_name,s.s_id,s.s_name列明,如果用"*"代替,则mybatis会自动匹配resultMap或者resultType中提供的列名, 如果某对象存在列映射的属性,但是在select 后面找不到这个列,则在返回结果中,该列多映射的值为null。 至此,对于一对一、一对多、视图查询都能很好的解决,主要还是要重点关注第四点说明。 from:https://www.cnblogs.com/wucj/p/5148813.html
View Details