张家界市住房和城乡建设局网站,小型互联网公司市值排名,标准的网络推广计划书的目录,网络营销做得比较好的企业SSM知识快速复习SpringIOCDIIOC容器在Spring中的实现常用注解Autowired注解的原理AOP相关术语作用动态代理实现原理事务Transactional事务属性#xff1a;只读事务属性#xff1a;超时事务属性#xff1a;回滚策略事务属性#xff1a;事务隔离级别事务属性#xff1a;事务…
SSM知识快速复习SpringIOCDIIOC容器在Spring中的实现常用注解Autowired注解的原理AOP相关术语作用动态代理实现原理事务Transactional事务属性只读事务属性超时事务属性回滚策略事务属性事务隔离级别事务属性事务传播行为SpringMVCRequestMappingRequestMapping的派生注解PathVariable获取请求参数通过ServletAPI获取通过控制器方法的形参获取请求参数RequestParamRequestHeaderCookieValue通过POJO获取请求参数域对象共享数据使用ServletAPI向request域对象共享数据使用ModelAndView向request域对象共享数据使用Model向request域对象共享数据使用map向request域对象共享数据使用ModelMap向request域对象共享数据Model、ModelMap、Map的关系向session域共享数据向application域共享数据Restful处理ajax请求RequestBodyRequestBody 获取json格式的请求参数ResponseBodyResponseBody响应浏览器json数据RestController文件上传和下载文件下载文件上传拦截器方法多个拦截器的执行顺序配置springmvc了解SpringMVC执行流程SpringMVC常用组件Handler 和 HandlerAdapter 区别SpringMVC的执行流程MyBatis特性使用MyBatis的增删改查获取参数值使用Param标识参数适合单个和多个字面量类型Map集合类型的参数实体类类型的参数自定义映射resultMapresultMap处理字段和属性的一对一映射关系多对一映射处理一对多映射处理分步查询动态SQLMyBatis的缓存MyBatis的一级缓存MyBatis的二级缓存二级缓存的相关配置MyBatis缓存查询的顺序MyBatis的逆向工程MyBatis-Plus特性使用流程BaseMapper -- CRUD通用Service -- CRUD常用注解TableNameTableIdTableFieldTableLogicEnumValue雪花算法条件构造器和常用接口Condition插件分页插件乐观锁代码生成器多数据源MyBatisX插件Spring
IOC
IOCInversion of Control翻译过来是反转控制。主动的从容器中获取所需要的资源变成被动的查找形式主动做菜变成点外卖
DI
DIDependency Injection翻译过来是依赖注入 IOC 就是一种反转控制的思想 而 DI 是对 IOC 的一种具体实现。说白了就是给spring所管理对象的属性进行赋值
IOC容器在Spring中的实现
IOC 容器中管理的组件也叫做 bean。在创建bean 之前首先需要创建 IOC 容器。
BeanFactory 这是 IOC 容器的基本实现是 Spring 内部使用的接口。面向 Spring 本身不提供给开发人员使用。ApplicationContext BeanFactory 的子接口提供了更多高级特性。面向 Spring 的使用者几乎所有场合都使用 ApplicationContext 而不是底层的 BeanFactory。
常用注解
Component将类标识为普通组件 Controller将类标识为控制层组件 Service将类标识为业务层组件 Repository将类标识为持久层组件 Autowired在成员变量上直接标记Autowired注解即可完成自动装配不需要提供setXxx()方法。
标识在成员变量上标识在set方法上为当前成员变量赋值的有参构造上
Autowired注解的原理
默认通过byType的方式在IOC容器中通过类型匹配某个bean为属性赋值若有多个类型匹配的bean此时会自动转换为byName的方式实现自动装配的效果 即将要赋值的属性的属性名作为bean的id匹配某个bean为属性赋值若byType和byName的方式都无法实现自动装配即IOC容器中有多个类型匹配的bean 且这些bean的id和要赋值的属性的属性名都不一致此时抛异常NoUniqueBeanDefinitionException此时可以在要赋值的属性上添加一个注解 Qualifier 通过该注解的value属性值指定某个bean的id将这个bean为属性赋值
注意若IOC容器中没有任何一个类型匹配的bean此时抛出异常NoSuchBeanDefinitionException 在Autowired注解中有个属性required默认值为true要求必须完成自动装配 可以将required设置为false此时能装配则装配无法装配则使用属性的默认值
AOP
例如日志的实现 核心就是解耦基于代理的设计模式相比于静态代理写死的不具有灵活性动态代理更加灵活。 通过预编译方式和运行期动态代理方式实现在不修改源代码的情况下给程序动态统一添加额外功能的一种技术。
相关术语
横切关注点从每个方法中抽取出来的同一类非核心业务。非核心代码通知每一个横切关注点上要做的事情需要的实现方法 类的方法 前置通知在被代理的目标方法前执行返回通知在被代理的目标方法成功结束后执行寿终正寝异常通知在被代理的目标方法异常结束后执行死于非命后置通知在被代理的目标方法最终结束后执行盖棺定论环绕通知使用try…catch…finally结构围绕整个被代理的目标方法包括上面四种通知对应的所有位置 切面封装通知方法的类类目标被代理的目标对象代理向目标对象应用通知之后创建的代理对象连接点抽取横切关注点的位置是一个概念而不涉及代码切入点定位连接点的方式。从代码角度来说是一个表达式
作用
简化代码把方法中固定位置的重复的代码抽取出来让被抽取的方法更专注于自己的核心功能 提高内聚性。 代码增强把特定的功能封装到切面类中看哪里有需要就往上套被套用了切面逻辑的方法就 被切面给增强了。
动态代理 动态代理InvocationHandlerJDK原生的实现方式需要被代理的目标类必须实现接口。因 为这个技术要求代理对象和目标对象实现同样的接口兄弟两个拜把子模式。cglib通过继承被代理的目标类认干爹模式实现代理所以不需要目标类实现接口。AspectJ本质上是静态代理将代理逻辑“织入”被代理的目标类编译得到的字节码文件所以最 终效果是动态的。weaver就是织入器。Spring只是借用了AspectJ中的注解。
// Aspect表示这个类是一个切面类
Aspect
// Component注解保证这个切面类能够放入IOC容器
Component
public class LogAspect {Before(execution(public int com.atguigu.aop.annotation.CalculatorImpl.*
(..)))public void beforeMethod(JoinPoint joinPoint){String methodName joinPoint.getSignature().getName();String args Arrays.toString(joinPoint.getArgs());System.out.println(Logger--前置通知方法名methodName参
数args);}After(execution(* com.atguigu.aop.annotation.CalculatorImpl.*(..)))public void afterMethod(JoinPoint joinPoint){String methodName joinPoint.getSignature().getName();System.out.println(Logger--后置通知方法名methodName);}AfterReturning(value execution(*
com.atguigu.aop.annotation.CalculatorImpl.*(..)), returning result)public void afterReturningMethod(JoinPoint joinPoint, Object result){String methodName joinPoint.getSignature().getName();System.out.println(Logger--返回通知方法名methodName结
果result);}AfterThrowing(value execution(*
com.atguigu.aop.annotation.CalculatorImpl.*(..)), throwing ex)public void afterThrowingMethod(JoinPoint joinPoint, Throwable ex){String methodName joinPoint.getSignature().getName();System.out.println(Logger--异常通知方法名methodName异常ex);}Around(execution(* com.atguigu.aop.annotation.CalculatorImpl.*(..)))public Object aroundMethod(ProceedingJoinPoint joinPoint){String methodName joinPoint.getSignature().getName();String args Arrays.toString(joinPoint.getArgs());Object result null;try {System.out.println(环绕通知--目标对象方法执行之前);//目标对象连接点方法的执行result joinPoint.proceed();System.out.println(环绕通知--目标对象方法返回值之后);} catch (Throwable throwable) {throwable.printStackTrace();System.out.println(环绕通知--目标对象方法出现异常时);} finally {System.out.println(环绕通知--目标对象方法执行完毕);}return result;}}加了Aspect注解后无法通过getBean获取实现对象而是应该通过代理对象进行访问可以使用接口获取对象因为代理对象和原对象的接口相同 要用代理对象才能获取到是因为使用了aop而aop的底层使用的就是动态代理所以要获取代理对象而获取代理对象要通过接口来进行获取。
实现原理
AOP的实现原理通常涉及以下几个方面 连接点Join PointAOP框架需要确定在什么地方如方法执行前、后或异常抛出时等注入额外的逻辑代码这个确定的位置就是连接点。 切面Aspect切面是一个模块化的横切关注点它定义了在切入点注入的额外逻辑代码。切面可以是一个类或一个通知Advice函数。 通知Advice通知是切面实际注入的代码逻辑它定义了在切入点执行前、后或抛出异常时需要执行的代码。 织入Weaving织入是将切面应用到目标对象上的过程。织入可以在编译时、类加载时或运行时进行。 切点Pointcut切点是一个表达式它定义了哪些切入点需要被织入。切点可以是一个方法名、一个正则表达式或者一个类、方法的匹配规则。 引入Introduction引入是在目标对象中添加新的方法或属性以增强其功能。 AOP框架通常会提供以上这些概念的API以便开发人员使用。通过AOP框架开发人员可以将不同的切面织入到目标对象中从而实现不同的横切关注点提高代码的可重用性和灵活性。
动态代理
动态代理是一种在运行时生成代理对象的技术它允许程序在运行时创建一个实现了给定接口的代理类对象该代理类对象可以拦截目标对象方法的调用并在调用前、调用后或异常抛出时注入额外的逻辑代码。这个代理类对象即为AOP中的切面。Java中有两种动态代理方式JDK动态代理和CGLIB动态代理。JDK动态代理是基于接口的动态代理它只能代理实现了接口的类而CGLIB动态代理是基于继承的动态代理它可以代理没有实现接口的类。在AOP中通常使用JDK动态代理来代理接口使用CGLIB动态代理来代理没有实现接口的类。动态代理是AOP实现的一种常用技术但并非AOP的全部实现原理还包括切点、通知、织入等概念和实现方式
事务Transactional
Transactional标识在方法上只会影响该方法 Transactional标识的类上会影响类中所有的方法
事务属性只读
Transactional(readOnly true)
事务属性超时
概括来说就是一句话超时回滚释放资源。
Transactional(timeout 3)事务属性回滚策略
Transactional(noRollbackFor ArithmeticException.class)默认只针对运行时异常回滚编译时异常不回滚 可以通过Transactional中相关属性设置回滚策略
rollbackFor属性需要设置一个Class类型的对象rollbackForClassName属性需要设置一个字符串类型的全类名noRollbackFor属性需要设置一个Class类型的对象rollbackFor属性需要设置一个字符串类型的全类名
事务属性事务隔离级别
Transactional(isolation Isolation.DEFAULT)//使用数据库默认的隔离级别
Transactional(isolation Isolation.READ_UNCOMMITTED)//读未提交
Transactional(isolation Isolation.READ_COMMITTED)//读已提交
Transactional(isolation Isolation.REPEATABLE_READ)//可重复读
Transactional(isolation Isolation.SERIALIZABLE)//串行化隔离级别一共有四种
读未提交READ UNCOMMITTED 允许Transaction01读取Transaction02未提交的修改。读已提交READ COMMITTED、 要求Transaction01只能读取Transaction02已提交的修改。可重复读REPEATABLE READ 确保Transaction01可以多次从一个字段中读取到相同的值即Transaction01执行期间禁止其它 事务对这个字段进行更新。串行化SERIALIZABLE 确保Transaction01可以多次从一个表中读取到相同的行在Transaction01执行期间禁止其它 事务对这个表进行添加、更新、删除操作。可以避免任何并发问题但性能十分低下。
事务属性事务传播行为
Transactional(propagation Propagation.REQUIRED)事务传播行为是指在一个事务中的多个操作之间的关系以及当一个事务方法调用另一个事务方法时这些事务之间的关系。在这种情况下需要确定调用方法时如何处理事务以确保整个操作的数据完整性和一致性。
在Spring框架中定义了7种事务传播行为 PROPAGATION_REQUIRED默认值如果当前已经存在一个事务则加入该事务否则创建一个新的事务。 PROPAGATION_SUPPORTS如果当前已经存在一个事务则加入该事务否则以非事务的方式执行。 PROPAGATION_MANDATORY如果当前已经存在一个事务则加入该事务否则抛出异常。 PROPAGATION_REQUIRES_NEW创建一个新的事务并挂起当前事务如果存在。 PROPAGATION_NOT_SUPPORTED以非事务的方式执行操作如果当前存在一个事务则挂起该事务。 PROPAGATION_NEVER以非事务的方式执行操作如果当前存在一个事务则抛出异常。 PROPAGATION_NESTED如果当前存在一个事务则在嵌套事务中执行操作否则创建一个新的事务。嵌套事务可以单独提交或回滚但是最终的提交或回滚操作将由最外层的事务控制。
通过指定事务传播行为可以在不同的方法之间控制事务的行为。根据具体的业务场景选择适当的事务传播行为可以保证数据的完整性和一致性。 事务挂起 事务挂起是指在嵌套事务中内部事务挂起外部事务的执行直到内部事务完成后再恢复外部事务的执行。嵌套事务是指在一个已经存在的事务中开启了新的事务。
当外部事务和内部事务使用相同的数据源时内部事务在执行期间会阻塞外部事务对于相同数据的访问这可能会导致性能问题或死锁问题。因此事务管理器提供了事务挂起的机制可以让内部事务暂停执行让外部事务继续执行从而避免死锁和性能问题。
在Java中使用JDBC或Hibernate等ORM框架进行数据库操作时可以通过设置事务传播行为为PROPAGATION_REQUIRES_NEW来开启一个新的事务。当内部事务执行时外部事务会被挂起直到内部事务完成后再恢复执行。在Spring框架中使用TransactionTemplate或Transactional注解来管理事务也可以通过设置事务传播行为来实现事务挂起。
SpringMVC
RequestMapping
RequestMapping标识一个类设置映射请求的请求路径的初始信息 RequestMapping标识一个方法设置映射请求请求路径的具体信息 RequestMapping注解的value属性是一个字符串类型的数组表示该请求映射能够匹配多个请求地址 所对应的请求 RequestMapping注解的method属性通过请求的请求方式get或post匹配请求映射 RequestMapping注解的method属性是一个RequestMethod类型的数组表示该请求映射能够匹配 多种请求方式的请求
RequestMapping(value {/testRequestMapping, /test},method {RequestMethod.GET, RequestMethod.POST}
)RequestMapping的派生注解
处理get请求的映射–GetMapping 处理post请求的映射–PostMapping 处理put请求的映射–PutMapping 处理delete请求的映射–DeleteMapping
PathVariable
占位符常用于RESTful风格中当请求路径中将某些数据通过路径的方式传输到服务器中就可以在相应的RequestMapping注解的value属性中通过占位符{xxx}表示传输的数据在通过PathVariable注解将占位符所表示的数据赋值给控制器方法的形参
RequestMapping(/testRest/{id}/{username})
public String testRest(PathVariable(id) String id, PathVariable(username)
String username){System.out.println(id:id,username:username);return success;
}获取请求参数
通过ServletAPI获取
HttpServletRequest类型的参数表示封装了当前请求的请求报文的对象
RequestMapping(/testParam)
public String testParam(HttpServletRequest request){String username request.getParameter(username);String password request.getParameter(password);System.out.println(username:username,password:password);return success;
}通过控制器方法的形参获取请求参数
在控制器方法的形参位置设置和请求参数同名的形参当浏览器发送请求匹配到请求映射时在 DispatcherServlet中就会将请求参数赋值给相应的形参
RequestMapping(/testParam)
public String testParam(String username, String password){System.out.println(username:username,password:password);return success;
}RequestParam
RequestParam是将请求参数和控制器方法的形参创建映射关系 RequestParam注解一共有三个属性
value指定为形参赋值的请求参数的参数名required设置是否必须传输此请求参数默认值为true 若设置为true时则当前请求必须传输value所指定的请求参数若没有传输该请求参数且没有设置 defaultValue属性则页面报错400Required String parameter ‘xxx’ is not present若设置为 false则当前请求不是必须传输value所指定的请求参数若没有传输则注解所标识的形参的值为 nulldefaultValue不管required属性值为true或false当value所指定的请求参数没有传输或传输的值 为时则使用默认值为形参赋值
RequestHeader
RequestHeader是将请求头信息和控制器方法的形参创建映射关系 RequestHeader注解一共有三个属性value、required、defaultValue用法同RequestParam
CookieValue
CookieValue是将cookie数据和控制器方法的形参创建映射关系 CookieValue注解一共有三个属性value、required、defaultValue用法同RequestParam
通过POJO获取请求参数
可以在控制器方法的形参位置设置一个实体类类型的形参此时若浏览器传输的请求参数的参数名和实 体类中的属性名一致那么请求参数就会为此属性赋值
RequestMapping(/testpojo)
public String testPOJO(User user){System.out.println(user);return success;
}域对象共享数据
使用ServletAPI向request域对象共享数据
RequestMapping(/testServletAPI)
public String testServletAPI(HttpServletRequest request){request.setAttribute(testScope, hello,servletAPI);return success;
}使用ModelAndView向request域对象共享数据
RequestMapping(/testModelAndView)
public ModelAndView testModelAndView(){/*** ModelAndView有Model和View的功能* Model主要用于向请求域共享数据* View主要用于设置视图实现页面跳转*/ModelAndView mav new ModelAndView();//向请求域共享数据mav.addObject(testScope, hello,ModelAndView);//设置视图实现页面跳转mav.setViewName(success);return mav;
}使用Model向request域对象共享数据
RequestMapping(/testModel)
public String testModel(Model model){model.addAttribute(testScope, hello,Model);return success;
}使用map向request域对象共享数据
RequestMapping(/testMap)
public String testMap(MapString, Object map){map.put(testScope, hello,Map);return success;
}使用ModelMap向request域对象共享数据
RequestMapping(/testModelMap)
public String testModelMap(ModelMap modelMap){modelMap.addAttribute(testScope, hello,ModelMap);return success;
}Model、ModelMap、Map的关系
Model、ModelMap、Map类型的参数其实本质上都是 BindingAwareModelMap 类型的
向session域共享数据
RequestMapping(/testSession)
public String testSession(HttpSession session){session.setAttribute(testSessionScope, hello,session);return success;
}向application域共享数据
RequestMapping(/testApplication)
public String testApplication(HttpSession session){ServletContext application session.getServletContext();application.setAttribute(testApplicationScope, hello,application);return success;
}Restful
Rest原理表单提交要使用REST的时候
表单提交会带上\_methodPUT请求过来被HiddenHttpMethodFilter拦截 请求是否正常并且是POST 获取到\_method的值。兼容以下请求PUT.DELETE.PATCH原生requestpost包装模式requesWrapper重写了getMethod方法返回的是传入的值。过滤器链放行的时候用wrapper。以后的方法调用getMethod是调用requesWrapper的。
HiddenHttpMethodFilter 处理put和delete请求的条件
当前请求的请求方式必须为post当前请求必须传输请求参数_method
处理ajax请求
RequestBody
RequestBody可以获取请求体信息使用RequestBody注解标识控制器方法的形参当前请求的请 求体就会为当前注解所标识的形参赋值
RequestMapping(/test/RequestBody)
public String testRequestBody(RequestBody String requestBody){}RequestBody 获取json格式的请求参数
对于json数据操作json的相关jar包gson或jackson处理此类请求参数可以将其转换为指定的实体类对象或map集合
在SpringMVC中直接使用RequestBody注解标识控制器方法的形参即可将此类请求参数转换为java对象
public void testRequestBody(RequestBody User user, HttpServletResponse
response) throws IOException {}ResponseBody
ResponseBody用于标识一个控制器方法可以将该方法的返回值直接作为响应报文的响应体响应到 浏览器
RequestMapping(/testResponseBody)
ResponseBody
public String testResponseBody(){//此时响应浏览器数据successreturn success;
}ResponseBody响应浏览器json数据
使用操作json数据的jar包gson或jackson将java对象转换为json字符串。 在SpringMVC中我们可以直接使用ResponseBody注解实现此功能 可以是listmap实体类
//响应浏览器list集合
RequestMapping(/test/ResponseBody/json)
ResponseBody
public ListUser testResponseBody(){User user1 new User(1001,admin1,123456,23,男);User user2 new User(1002,admin2,123456,23,男);User user3 new User(1003,admin3,123456,23,男);ListUser list Arrays.asList(user1, user2, user3);return list;
}RestController
RestController注解是springMVC提供的一个复合注解标识在控制器的类上就相当于为类添加了 Controller注解并且为其中的每个方法添加了ResponseBody注解
文件上传和下载
文件下载
ResponseEntity用于控制器方法的返回值类型该控制器方法的返回值就是响应到浏览器的响应报文使用ResponseEntity实现下载文件的功能
RequestMapping(/testDown)
public ResponseEntitybyte[] testResponseEntity(HttpSession session) throws
IOException {//获取ServletContext对象ServletContext servletContext session.getServletContext();//获取服务器中文件的真实路径String realPath servletContext.getRealPath(/static/img/1.jpg);//创建输入流InputStream is new FileInputStream(realPath);//创建字节数组byte[] bytes new byte[is.available()];//将流读到字节数组中is.read(bytes);//创建HttpHeaders对象设置响应头信息MultiValueMapString, String headers new HttpHeaders();//设置要下载方式以及下载文件的名字headers.add(Content-Disposition, attachment;filename1.jpg);//设置响应状态码HttpStatus statusCode HttpStatus.OK;//创建ResponseEntity对象ResponseEntitybyte[] responseEntity new ResponseEntity(bytes, headers,
statusCode);//关闭输入流is.close();return responseEntity;
}文件上传
文件上传要求form表单的请求方式必须为post并且添加属性enctype“multipart/form-data” SpringMVC中将上传的文件封装到MultipartFile对象中通过此对象可以获取文件相关信息
RequestMapping(/testUp)
public String testUp(MultipartFile photo, HttpSession session) throws
IOException {//获取上传的文件的文件名String fileName photo.getOriginalFilename();//处理文件重名问题String hzName fileName.substring(fileName.lastIndexOf(.));fileName UUID.randomUUID().toString() hzName;//获取服务器中photo目录的路径ServletContext servletContext session.getServletContext();String photoPath servletContext.getRealPath(photo);File file new File(photoPath);if(!file.exists()){file.mkdir();}String finalPath photoPath File.separator fileName;//实现上传功能photo.transferTo(new File(finalPath));return success;
}拦截器
SpringMVC中的拦截器用于拦截控制器方法的执行 SpringMVC中的拦截器需要实现HandlerInterceptor
方法
preHandle控制器方法执行之前执行preHandle()其boolean类型的返回值表示是否拦截或放行返 回true为放行即调用控制器方法返回false表示拦截即不调用控制器方法postHandle控制器方法执行之后执行postHandle()afterCompletion处理完视图和模型数据渲染视图完毕之后执行afterCompletion() 多个拦截器的执行顺序
若每个拦截器的preHandle()都返回true 此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关 preHandle()会按照配置的顺序执行而postHandle()和afterCompletion()会按照配置的反序执行若某个拦截器的preHandle()返回了false preHandle()返回false和它之前的拦截器的preHandle()都会执行postHandle()都不执行返回false 的拦截器之前的拦截器的afterCompletion()会执行
配置springmvc了解
在SpringMVC的配置中需要配置以下文件
1 、组件扫描器(Compnent-Scan) 2 、Thymeleaf视图解析器 3 、MVC视图解析器(View-Controller) 4 、 静态资源访问(Default-servlet-handler) 5 、MVC注解驱动(annotation-driver) 6 、文件上传解析器(CommonsMultiPartResolver) 7 、异常处理器(SimpleMappingExceptionResolver) 8 、拦截器(InterCeptor)
Configuration//将当前类标识为配置类
ComponentScan// 1 、组件扫描器
EnableWebMvc// 5 、MVC注解驱动
public class implements WebMvcConfigurer{ //实现WebMvcConfigurer 接口
// 4 、配置静态资源访问 Ctrlo选择configureDefaultServletHandlingOverridepublic void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {//enable开启静态资源访问configurer.enable();}// 8 、配置拦截器 Ctrlo选择addInterCeptorOverridepublic void addInterceptors(InterceptorRegistry registry) {//new一个拦截器对象TestInterceptor testInterceptor new TestInterceptor();//添加拦截器类().添加拦截的路径()//addInterceptor(HandlerInterceptor interceptor)类型是拦截器//所以需要new一个拦截器对象registry.addInterceptor(testInterceptor).addPathPatterns(/**).excludePathPatterns(/abc);}// 3 、配置mvc视图解析器 Ctrlo选择addViewControllersOverridepublic void addViewControllers(ViewControllerRegistry registry) {//添加路径(/hello).设置跳转的视图名(hello)registry.addViewController(/hello).setViewName(hello);}// 6 、配置文件上传解析器 Ctrlo选择MultipartResolverBean //要创建一个对象 用Bean注解public MultipartResolver multipartResolver(){//MultipartResolver只是一个接口 所以要new它的实现类CommonsMultipartResolver commonsMultipartResolver new CommonsMultipartResolver();return commonsMultipartResolver;}//另一种写法
// Bean
// public CommonsMultipartResolver multipartResolver(){
// return new CommonsMultipartResolver();
// }// 7 、配置异常处理器 Ctrlo选择configureHandlerExceptionResolverspublic void configureHandlerExceptionResolvers(ListHandlerExceptionResolver resolvers) {//配置beanSimpleMappingExceptionResolver exceptionResolver new SimpleMappingExceptionResolver();//创建两个属性exceptionMapping、exceptionAttribute;//new一个property文件进行键值对的传参Properties prop new Properties();//传入异常因为键值对是String类型所以不能用put方法(Object key,Object Value)prop.setProperty(java.lang.ArithmeticException,error);//将prop属性传给异常映射exceptionResolver.setExceptionMappings(prop);//将异常信息在请求域中进行共享exceptionResolver.setExceptionAttribute(exception);//添加异常处理器resolvers.add(exceptionResolver);}/*** 2 、配置Thymeleaf解析器*///配置生成模板解析器Beanpublic SpringResourceTemplateResolver templateResolver() {SpringResourceTemplateResolver springResourceTemplateResolver new SpringResourceTemplateResolver();springResourceTemplateResolver.setApplicationContext(ContextLoader.getCurrentWebApplicationContext());springResourceTemplateResolver.setPrefix(/WEB-INF/templates/);springResourceTemplateResolver.setSuffix(.html);springResourceTemplateResolver.setCharacterEncoding(UTF-8);springResourceTemplateResolver.setTemplateMode(TemplateMode.HTML);return springResourceTemplateResolver;}//生成模板引擎并为模板引擎注入模板解析器Beanpublic SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {SpringTemplateEngine templateEngine new SpringTemplateEngine();templateEngine.setTemplateResolver(templateResolver);return templateEngine;}//生成视图解析器并未解析器注入模板引擎Beanpublic ViewResolver viewResolver(SpringTemplateEngine templateEngine) {ThymeleafViewResolver viewResolver new ThymeleafViewResolver();viewResolver.setCharacterEncoding(UTF-8);viewResolver.setTemplateEngine(templateEngine);return viewResolver;}
}SpringMVC执行流程
SpringMVC常用组件
DispatcherServlet前端控制器不需要工程师开发由框架提供 作用统一处理请求和响应整个流程控制的中心由它调用其它组件处理用户的请求HandlerMapping处理器映射器不需要工程师开发由框架提供 作用根据请求的url、method等信息查找Handler即控制器方法Handler处理器需要工程师开发 作用在DispatcherServlet的控制下Handler对具体的用户请求进行处理HandlerAdapter处理器适配器不需要工程师开发由框架提供 作用通过HandlerAdapter对处理器控制器方法进行执行ViewResolver视图解析器不需要工程师开发由框架提供 作用进行视图解析得到相应的视图例如ThymeleafView、InternalResourceView、RedirectViewView视图 作用将模型数据通过页面展示给用户
Handler 和 HandlerAdapter 区别
在Spring MVC中Handler处理器和HandlerAdapter处理器适配器是两个不同的概念它们的作用和职责也不同。
Handler负责处理客户端请求它通常是一个具有特定注解例如RequestMapping的Java类或方法用于处理客户端请求并生成相应的响应结果。Handler的职责是根据客户端请求的URL、参数等信息执行相应的业务逻辑并将结果返回给客户端。
HandlerAdapter是Spring MVC框架中的一个核心组件它的作用是根据Handler的类型将其适配为可以被Spring MVC框架处理的对象。不同类型的Handler可能需要不同的处理逻辑因此需要不同的HandlerAdapter来进行适配。
HandlerAdapter的主要职责是将Handler的执行结果转换为ModelAndView或者其他形式的响应结果使其可以被视图解析器ViewResolver处理并返回给客户端。因此HandlerAdapter起到了框架和Handler之间的桥梁作用。
总结来说Handler负责业务处理而HandlerAdapter负责将Handler适配为可以被框架处理的对象。在请求处理的整个流程中Handler和HandlerAdapter是相互配合的共同完成请求处理和响应生成的任务。
SpringMVC的执行流程
用户向服务器发送请求请求被SpringMVC 前端控制器 DispatcherServlet捕获。DispatcherServlet对请求URL进行解析得到请求资源标识符URI判断请求URI对应的映射 不存在 i. 再判断是否配置了mvc:default-servlet-handler ii. 如果没配置则控制台报映射查找不到客户端展示404错误 iii. 如果有配置则访问目标资源一般为静态资源如JS,CSS,HTML找不到客户端也会展示404错误 根据该URI调用HandlerMapping获得该Handler配置的所有相关的对象包括Handler对象以及Handler对象对应的拦截器最后以HandlerExecutionChain执行链对象的形式返回。DispatcherServlet 根据获得的Handler选择一个合适的HandlerAdapter。如果成功获得HandlerAdapter此时将开始执行拦截器的preHandler(…)方法【正向】提取Request中的模型数据填充Handler入参开始执行HandlerController)方法处理请求。在填充Handler的入参过程中根据你的配置Spring将帮你做一些额外的工作 HttpMessageConveter 将请求消息如Json、xml等数据转换成一个对象将对象转换为指定 的响应信息数据转换对请求消息进行数据转换。如String转换成Integer、Double等数据格式化对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等数据验证 验证数据的有效性长度、格式等验证结果存储到BindingResult或Error中 Handler执行完成后向DispatcherServlet 返回一个ModelAndView对象。此时将开始执行拦截器的postHandle(…)方法【逆向】。根据返回的ModelAndView此时会判断是否存在异常如果存在异常则执行HandlerExceptionResolver进行异常处理选择一个适合的ViewResolver进行视图解析根据Model和View来渲染视图。渲染视图完毕执行拦截器的afterCompletion(…)方法【逆向】。将渲染结果返回给客户端。
MyBatis
特性
MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集MyBatis可以使用简单的XML或注解用于配置和原始映射将接口和Java的POJOPlain Old Java Objects普通的Java对象映射成数据库中的记录MyBatis 是一个 半自动的ORMObject Relation Mapping框架
使用
创建mapper接口
public interface UserMapper {/*** 添加用户信息*/int insertUser();
}创建MyBatis的映射文件
?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapperPUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtd
mapper namespacecom.atguigu.mybatis.mapper.UserMapper!--int insertUser();--insert idinsertUserinsert into t_user values(null,张三,123,23,女)/insert
/mapper映射文件的命名规则 表所对应的实体类的类名Mapper.xml 例如表t_user映射的实体类为User所对应的映射文件为UserMapper.xml 因此一个映射文件对应一个实体类对应一张表的操作 MyBatis映射文件用于编写SQL访问以及操作表中的数据 MyBatis映射文件存放的位置是src/main/resources/mappers目录下MyBatis中可以面向接口操作数据要保证两个一致 mapper接口的全类名和映射文件的命名空间namespace保持一致mapper接口中方法的方法名和映射文件中编写SQL的标签的id属性保持一致
MyBatis的增删改查
添加
!--int insertUser();--
insert idinsertUserinsert into t_user values(null,admin,123456,23,男)
/insert删除
!--int deleteUser();--
delete iddeleteUserdelete from t_user where id 7
/delete修改
!--int updateUser();--
update idupdateUserupdate t_user set usernameybc,password123 where id 6
/update查询一个实体类对象
!--User getUserById();--
select idgetUserById resultTypecom.atguigu.mybatis.bean.Userselect * from t_user where id 2
/select查询集合
!--ListUser getUserList();--
select idgetUserList resultTypecom.atguigu.mybatis.bean.Userselect * from t_user
/select查询count数据
!--int getCount();--
select idgetCount resultType_integerselect count(id) from t_user
/select查询一条数据为map集合
!--MapString, Object getUserToMap(Param(id) int id);--
select idgetUserToMap resultTypemapselect * from t_user where id #{id}
/select
!--结果{password123456, sex男, id1, age23, usernameadmin}--查询多条数据为map集合
!--ListMapString, Object getAllUserToMap();--
select idgetAllUserToMap resultTypemapselect * from t_user
/select模糊查询
!--ListUser testMohu(Param(mohu) String mohu);--
select idtestMohu resultTypeUserselect * from t_user where username like %#{mohu}%
/select批量删除
!--int deleteMore(Param(ids) String ids);--
delete iddeleteMoredelete from t_user where id in (${ids})
/delete动态设置表名
!--ListUser getAllUser(Param(tableName) String tableName);--
select idgetAllUser resultTypeUserselect * from ${tableName}
/select添加功能获取自增的主键
keyProerty的值就是主键会被保存在所传递参数对象上的那个属性
!--int insertUser(User user);--
insert idinsertUser useGeneratedKeystrue keyPropertyidinsert into t_user values(null,#{username},#{password},#{age},#{sex})
/insert注意
查询的标签select必须设置属性resultType或resultMap用于设置实体类和数据库表的映射 关系 resultType自动映射用于属性名和表中字段名一致的情况resultMap自定义映射用于一对多或多对一或字段名和属性名不一致的情况 当查询的数据为多条时不能使用实体类作为返回值只能使用集合否则会抛出异常
获取参数值
${}和#{} ${}的本质就是字符串拼接 #{}的本质就是占位符赋值
使用Param标识参数适合单个和多个字面量类型
通过Param注解标识mapper接口中的方法参数
Map集合类型的参数
只需要通过${}和#{}访问map集合的键就可以获取相对应的值注意${}需要手动加单引号
实体类类型的参数
使用${}和#{}通过访问实体类对象中的属性名获取属性值注意${}需要手动加单引号
自定义映射resultMap
resultMap处理字段和属性的一对一映射关系
resultMap设置自定义映射属性
id表示自定义映射的唯一标识type查询的数据要映射的实体类的类型子标签 id设置主键的映射关系result设置普通字段的映射关系association设置多对一的映射关系collection设置一对多的映射关系 属性property设置映射关系中实体类中的属性名column设置映射关系中表中的字段名
resultMap iduserMap typeUserid propertyid columnid/idresult propertyuserName columnuser_name/resultresult propertypassword columnpassword/resultresult propertyage columnage/resultresult propertysex columnsex/result
/resultMap
!--ListUser testMohu(Param(mohu) String mohu);--
select idtestMohu resultMapuserMap!--select * from t_user where username like %${mohu}%--select id,user_name,password,age,sex from t_user where user_name like
concat(%,#{mohu},%)
/select多对一映射处理
association处理多对一的映射关系property需要处理多对的映射关系的属性名javaType该属性的类型
resultMap idempDeptMap typeEmpid columneid propertyeid/idresult columnename propertyename/resultresult columnage propertyage/resultresult columnsex propertysex/resultassociation propertydept javaTypeDeptid columndid propertydid/idresult columndname propertydname/result/association
/resultMap
!--Emp getEmpAndDeptByEid(Param(eid) int eid);--
select idgetEmpAndDeptByEid resultMapempDeptMapselect emp.*,dept.* from t_emp emp left join t_dept dept on emp.did
dept.did where emp.eid #{eid}
/select多对一关系是指多个对象都关联到同一个对象的关系也可以称之为“多个小的对象引用一个大的对象”。下面举一个生活中的例子来说明。
假设有一个学校和多个班级每个班级都有多个学生。那么可以把学校看作是“一个大的对象”每个班级看作是“一个小的对象”每个学生看作是“一个更小的对象”。这样就形成了一个多对一的关系多个班级多个小的对象关联到同一个学校一个大的对象。
在这个例子中学校是一个全局的实体班级是一个局部的实体而学生则是班级中的局部实体。当需要查询一个学校的所有班级和学生信息时可以通过多对一的关系将所有班级和学生的信息与学校的信息进行关联从而得到完整的信息。
在数据库设计中多对一的关系也非常常见例如一个订单一个大的对象可以包含多个商品多个小的对象而多个订单多个小的对象都属于同一个客户一个大的对象。这种情况下可以通过多对一的关系将所有商品和订单的信息与客户的信息进行关联从而得到完整的客户信息。
一对多映射处理
collection
resultMap iddeptEmpMap typeDeptid propertydid columndid/idresult propertydname columndname/result!--ofType设置collection标签所处理的集合属性中存储数据的类型--collection propertyemps ofTypeEmpid propertyeid columneid/idresult propertyename columnename/resultresult propertyage columnage/resultresult propertysex columnsex/result/collection
/resultMap
!--Dept getDeptEmpByDid(Param(did) int did);--
select idgetDeptEmpByDid resultMapdeptEmpMapselect dept.*,emp.* from t_dept dept left join t_emp emp on dept.did emp.did where dept.did #{did}
/select分步查询
分步查询的优点可以实现延迟加载但是必须在核心配置文件中设置全局配置信息
lazyLoadingEnabled延迟加载的全局开关。当开启时所有关联对象都会延迟加载aggressiveLazyLoading当开启时任何方法的调用都会加载该对象的所有属性。 否则每个 属性会按需加载 此时就可以实现按需加载获取的数据是什么就只会执行相应的sql。此时可通过association和 collection中的fetchType属性设置当前的分步查询是否使用延迟加载fetchTypelazy(延迟加 载)|eager(立即加载)
resultMap iddeptEmpStep typeDeptid propertydid columndid/idresult propertydname columndname/resultcollection propertyemps fetchTypeeager
selectcom.atguigu.MyBatis.mapper.EmpMapper.getEmpListByDid columndid
/collection
/resultMap
!--Dept getDeptByStep(Param(did) int did);--
select idgetDeptByStep resultMapdeptEmpStepselect * from t_dept where did #{did}
/select动态SQL
Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能它存在的意义是为了解决 拼接SQL语句字符串时的痛点问题。
ifwheretrimchoose、when、otherwise 相当于if…else if…elseforeachSQL片段 sql片段可以记录一段公共sql片段在使用的地方通过include标签进行引入
MyBatis的缓存
只针对查询功能有效
MyBatis的一级缓存
一级缓存是 MyBatis 中默认开启的缓存它是指在同一个 SqlSession 中执行的相同 SQL 语句所查询的结果会被缓存起来下一次执行相同 SQL 语句时会直接从缓存中获取而不会再去查询数据库。一级缓存的生命周期很短当 SqlSession 关闭时一级缓存也会被清空。
使一级缓存失效的四种情况
不同的SqlSession对应不同的一级缓存同一个SqlSession但是查询条件不同同一个SqlSession两次查询期间执行了任何一次增删改操作同一个SqlSession两次查询期间手动清空了缓存
MyBatis的二级缓存
二级缓存是指在同一个 namespace 下的不同 SqlSession 中执行相同 SQL 语句所查询的结果会被缓存起来下一次执行相同 SQL 语句时会直接从缓存中获取而不会再去查询数据库。二级缓存的生命周期比一级缓存长它会随着 SqlSessionFactory 的生命周期结束而结束。因为二级缓存是在多个 SqlSession 中共享的所以在进行增删改操作时会自动清空所有与该 namespace 相关的二级缓存。
使二级缓存失效的情况 两次查询之间执行了任意的增删改会使一级和二级缓存同时失效
总的来说一级缓存是在 SqlSession 级别的缓存而二级缓存是在 namespace 级别的缓存。在使用 MyBatis 进行开发时一般建议使用默认的一级缓存并根据实际情况进行配置和调整。二级缓存虽然可以提高查询效率但也存在一些问题例如缓存数据过期、数据不一致等需要谨慎使用。
二级缓存的相关配置
eviction属性缓存回收策略 LRULeast Recently Used – 最近最少使用的移除最长时间不被使用的对象。 FIFOFirst in First out – 先进先出按对象进入缓存的顺序来移除它们。 SOFT – 软引用移除基于垃圾回收器状态和软引用规则的对象。 WEAK – 弱引用更积极地移除基于垃圾收集器状态和弱引用规则的对象。 默认的是 LRU。flushInterval属性刷新间隔单位毫秒 默认情况是不设置也就是没有刷新间隔缓存仅仅调用语句时刷新size属性引用数目正整数 代表缓存最多可以存储多少个对象太大容易导致内存溢出readOnly属性只读true/false true只读缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了 很重要的性能优势。 false读写缓存会返回缓存对象的拷贝通过序列化。这会慢一些但是安全因此默认是 false。
MyBatis缓存查询的顺序
先查询二级缓存因为二级缓存中可能会有其他程序已经查出来的数据可以拿来直接使用。如果二级缓存没有命中再查询一级缓存如果一级缓存也没有命中则查询数据库SqlSession关闭之后一级缓存中的数据会写入二级缓存
MyBatis的逆向工程
正向工程先创建Java实体类由框架负责根据实体类生成数据库表。Hibernate是支持正向工程 的。逆向工程先创建数据库表由框架负责根据数据库表反向生成如下资源 Java实体类Mapper接口Mapper映射文件
执行MBG插件的generate目标
MyBatis-Plus
特性
无侵入只做增强不做改变引入它不会对现有工程产生影响如丝般顺滑损耗小启动即会自动注入基本 CURD性能基本无损耗直接面向对象操作强大的 CRUD 操作内置通用 Mapper、通用 Service仅仅通过少量配置即可实现单表大部分 CRUD 操作更有强大的条件构造器满足各类使用需求支持 Lambda 形式调用通过 Lambda 表达式方便的编写各类查询条件无需再担心字段写错支持主键自动生成支持多达 4 种主键策略内含分布式唯一 ID 生成器 - Sequence可自由 配置完美解决主键问题支持 ActiveRecord 模式支持 ActiveRecord 形式调用实体类只需继承 Model 类即可进行强 大的 CRUD 操作支持自定义全局通用操作支持全局通用方法注入 Write once, use anywhere 内置代码生成器采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码支持模板引擎更有超多自定义配置等您来使用内置分页插件基于 MyBatis 物理分页开发者无需关心具体操作配置好插件之后写分页等 同于普通 List 查询分页插件支持多种数据库支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、 Postgre、SQLServer 等多种数据库内置性能分析插件可输出 SQL 语句以及其执行时间建议开发测试时启用该功能能快速揪出 慢查询内置全局拦截插件提供全表 delete 、 update 操作智能分析阻断也可自定义拦截规则预防 误操作
使用
流程
配置yml
spring:# 配置数据源信息datasource:# 配置数据源类型type: com.zaxxer.hikari.HikariDataSource# 配置连接数据库信息driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/mybatis_plus?characterEncodingutf-
8useSSLfalseusername: rootpassword: 123456在Spring Boot启动类中添加MapperScan注解扫描mapper包
SpringBootApplication
MapperScan(com.atguigu.mybatisplus.mapper)
public class MybatisplusApplication {public static void main(String[] args) {SpringApplication.run(MybatisplusApplication.class, args);}
}添加实体
Data //lombok注解
public class User {private Long id;private String name;private Integer age;private String email;
}添加mapper
public interface UserMapper extends BaseMapperUser {
}BaseMapper是MyBatis-Plus提供的模板mapper其中包含了基本的CRUD方法泛型为操作的 实体类型
添加日志
# 配置MyBatis日志
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplBaseMapper – CRUD
插入 MyBatis-Plus在实现插入数据时会默认基于雪花算法的策略生成id
Test
public void testInsert(){User user new User(null, 张三, 23, zhangsanatguigu.com);//INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )int result userMapper.insert(user);System.out.println(受影响行数result);//1475754982694199298System.out.println(id自动获取user.getId());
}删除
通过id删除记录
Test
public void testDeleteById(){//通过id删除用户信息//DELETE FROM user WHERE id?int result userMapper.deleteById(1475754982694199298L);System.out.println(受影响行数result);
}通过id批量删除记录
Test
public void testDeleteBatchIds(){//通过多个id批量删除//DELETE FROM user WHERE id IN ( ? , ? , ? )ListLong idList Arrays.asList(1L, 2L, 3L);int result userMapper.deleteBatchIds(idList);System.out.println(受影响行数result);
}通过map条件删除记录
Test
public void testDeleteByMap(){//根据map集合中所设置的条件删除记录//DELETE FROM user WHERE name ? AND age ?MapString, Object map new HashMap();map.put(age, 23);map.put(name, 张三);int result userMapper.deleteByMap(map);System.out.println(受影响行数result);
}修改
Test
public void testUpdateById(){User user new User(4L, admin, 22, null);//UPDATE user SET name?, age? WHERE id?int result userMapper.updateById(user);System.out.println(受影响行数result);
}查询
根据id查询用户信息
Test
public void testSelectById(){//根据id查询用户信息//SELECT id,name,age,email FROM user WHERE id?User user userMapper.selectById(4L);System.out.println(user);
}根据多个id查询多个用户信息
Test
public void testSelectBatchIds(){//根据多个id查询多个用户信息//SELECT id,name,age,email FROM user WHERE id IN ( ? , ? )ListLong idList Arrays.asList(4L, 5L);ListUser list userMapper.selectBatchIds(idList);list.forEach(System.out::println);
}通过map条件查询用户信息
Test
public void testSelectByMap(){//通过map条件查询用户信息//SELECT id,name,age,email FROM user WHERE name ? AND age ?MapString, Object map new HashMap();map.put(age, 22);map.put(name, admin);ListUser list userMapper.selectByMap(map);list.forEach(System.out::println);
}查询所有数据
Test
public void testSelectList(){//查询所有用户信息//SELECT id,name,age,email FROM userListUser list userMapper.selectList(null);list.forEach(System.out::println);
}BaseMapper中的方法大多方法中都有Wrapper类型的形参此为条件构造器可针 对于SQL语句设置不同的条件若没有条件则可以为该形参赋值null即查询删除/修改所 有数据
通用Service – CRUD 通用 Service CRUD 封装IService接口进一步封装 CRUD 采用 get 查询单行 remove 删 除 list 查询集合 page 分页 前缀命名方式区分 Mapper 层避免混淆 MyBatis-Plus中有一个接口 IService和其实现类 ServiceImpl封装了常见的业务层逻辑 创建
/*** UserService继承IService模板提供的基础功能*/
public interface UserService extends IServiceUser {}/*** ServiceImpl实现了IService提供了IService中基础功能的实现* 若ServiceImpl无法满足业务需求则可以使用自定的UserService定义方法并在实现类中实现*/
Service
public class UserServiceImpl extends ServiceImplUserMapper, User implements
UserService {}查询
Autowired
private UserService userService;
Test
public void testGetCount(){long count userService.count();System.out.println(总记录数 count);
}批量插入 有id是修改没有id是添加
Test
public void testSaveBatch(){// SQL长度有限制海量数据插入单条SQL无法实行// 因此MP将批量插入放在了通用Service中实现而不是通用MapperArrayListUser users new ArrayList();for (int i 0; i 5; i) {User user new User();user.setName(ybc i);user.setAge(20 i);users.add(user);}//SQL:INSERT INTO t_user ( username, age ) VALUES ( ?, ? )userService.saveBatch(users);
}常用注解
TableName
MyBatis-Plus在确定操作的表时默认操作的表名和实体类型的类名一致
在实体类类型上添加TableName(“t_user”)标识实体类对应的表
全局配置
mybatis-plus:configuration:# 配置MyBatis日志log-impl: org.apache.ibatis.logging.stdout.StdOutImplglobal-config:db-config:# 配置MyBatis-Plus操作表的默认前缀table-prefix: t_TableId
在实体类中uid属性上通过TableId将其标识为主键
value属性 指定表中的主键字段若实体类中主键对应的属性为id而表中表示主键的字段为uidtype属性 type属性用来定义主键策略 IdType.ASSIGN_ID默认: 基于雪花算法的策略生成数据idIdType.AUTO 使用数据库的自增策略
全局主键策略
mybatis-plus:configuration:# 配置MyBatis日志log-impl: org.apache.ibatis.logging.stdout.StdOutImplglobal-config:db-config:# 配置MyBatis-Plus操作表的默认前缀table-prefix: t_# 配置MyBatis-Plus的主键策略id-type: autoTableField
保证实体类中的属性名和表中的字段名一致 默认配置 实体类属性userName表中字段user_name此时MyBatis-Plus会自动将下划线命名风格转化为驼峰命名风格
TableLogic
逻辑删除假删除将对应数据中代表是否被删除字段的状态修改为“被删除状态”之后在数据库 中仍旧能看到此条数据记录
默认是0 - 未删除删除是1 - 已删除
EnumValue
表中的有些字段值是固定的例如性别男或女此时我们可以使用MyBatis-Plus的通用枚举来实现
配置
mybatis-plus:configuration:# 配置MyBatis日志log-impl: org.apache.ibatis.logging.stdout.StdOutImplglobal-config:db-config:# 配置MyBatis-Plus操作表的默认前缀table-prefix: t_# 配置MyBatis-Plus的主键策略id-type: auto# 配置扫描通用枚举type-enums-package: com.atguigu.mybatisplus.enums雪花算法
单表数据拆分有两种方式垂直分表和水平分表 水平分表相比垂直分表会引入更多的复杂性例如要求全局唯一的数据id该如何处理
雪花算法是由Twitter公布的分布式主键生成算法它能够保证不同表的主键的不重复性以及相同表的主键的有序性。
原理
长度共64bit一个long型
一个符号位1bit标识由于long基本类型在Java中是带符号的最高位是符号位正数是0负数是1所以id一般是正数最高位是0。41bit时间截(毫秒级)存储的是时间截的差值当前时间截 - 开始时间截)结果约等于69.73年。10bit作为机器的ID5个bit是数据中心5个bit的机器ID可以部署在1024个节点。12bit作为毫秒内的流水号意味着每个节点在每毫秒可以产生 4096 个 ID。
条件构造器和常用接口
Wrapper 条件构造抽象类最顶端父类 AbstractWrapper 用于查询条件封装生成 sql 的 where 条件 QueryWrapper 查询条件封装UpdateWrapper Update 条件封装AbstractLambdaWrapper 使用Lambda 语法 LambdaQueryWrapper 用于Lambda语法使用的查询WrapperLambdaUpdateWrapper Lambda 更新封装Wrapper
Condition
先判断用户是否选择了这些条件若选择则需要组装该条件若没有选择则一定不能组装以免影响SQL执行的结果 wrapper中第一个一般是condition条件
插件
分页插件
乐观锁
添加Version
原理
取出记录时获取当前version
SELECT id,name,price,version FROM product WHERE id1更新时version 1如果where语句中的version版本不对则更新失败
UPDATE product SET priceprice50, versionversion 1 WHERE id1 AND
version1配置
Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){MybatisPlusInterceptor interceptor new MybatisPlusInterceptor();//添加分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//添加乐观锁插件interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return interceptor;
}代码生成器
多数据源
适用于多种场景纯粹多库、 读写分离、 一主多从、 混合模式等 配置
spring:# 配置数据源信息datasource:dynamic:# 设置默认的数据源或者数据源组,默认值即为masterprimary: master# 严格匹配数据源,默认false.true未匹配到指定数据源时抛异常,false使用默认数据源strict: falsedatasource:master:url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncodingutf-
8useSSLfalsedriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: 123456slave_1:url: jdbc:mysql://localhost:3306/mybatis_plus_1?characterEncodingutf-
8useSSLfalsedriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: 123456使用 DS(“master”) //指定所操作的数据源
DS(master) //指定所操作的数据源
Service
public class UserServiceImpl extends ServiceImplUserMapper, User implements
UserService {
}MyBatisX插件
在真正开发过程中MyBatis-Plus并不能为我们解决所有问题例如一些复杂的SQL多表联查我们就需要自己去编写代码和SQL语句我们该如何快速的解决这个问题呢这个时候可以使用MyBatisX插件