搜索词>>事务唯一id 耗时0.0050
  • Log4j2 ThreadContext使用详解_日志跟踪id实现

    概述       Log4j2 ThreadContext允许您使用多个唯一的标签标记日志语句,以分析日志,同时在运行时诊断问题-主要是在多线程应用程序中,其中应用程序会在短时间内生成大量日志概述       Log4j2 ThreadContext允许您使用多个唯一的标签标记日志语句,以分析日志,同时在运行时诊断问题-主要是在多线程应用程序中,其中应用程序会在短时间内生成大量日志。 例如。 您可能要扫描所有日志以查找特定的用户事务或完成会话。 此过程也称为鱼标记(即,在每个log语句中添加一些额外的上下文信息)。 鱼标签可以帮助使用自动工具来记录日志,例如Splunk。让我们看看如何使用ThreadContext类在log4j2中进行捕获标记。在ThreadContext中添加容器信息为了唯一标记每个请求,ThreadContext提供了put(String key,String value)方法,该方法接受一个键及其值。 您可以根据需要添加任意数量的标签以捕获整个上下文信息。 请注意,ThreadContext类的所有方法都是静态的。import java.util.UUID; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.ThreadContext; public class Log4j2HelloWorldExample { private static final Logger LOGGER = LogManager.getLogger(Log4j2HelloWorldExample.class.getName()); public static void main(String[] args) { //Add context information ThreadContext.put("id", UUID.randomUUID().toString()); ThreadContext.put("ipAddress", "192.168.21.9"); LOGGER.debug("Debug Message Logged !!"); LOGGER.info("Info Message Logged !!"); LOGGER.debug("Another Debug Message !!"); //Clear the map ThreadContext.clearMap(); LOGGER.debug("Thread Context Cleaned up !!"); LOGGER.debug("Log message with no context information !!"); } }或者,您可以将ThreadContext的堆栈实现与ThreadContext.push(String value)一起使用,如下所示: //Add context information ThreadContext.push(UUID.randomUUID().toString()); ThreadContext.push("192.168.21.9"); LOGGER.debug("Debug Message Logged !!"); LOGGER.info("Info Message Logged !!"); LOGGER.debug("Another Debug Message !!"); //Clear the map ThreadContext.clearStack(); LOGGER.debug("Thread Context Cleaned up !!"); LOGGER.debug("Log message with no context information !!");事务结束或不再需要上下文信息之后,可以使用ThreadContext.clearMap()方法清空信息。 ThreadContext的Stack和Map是按线程管理的,默认情况下基于ThreadLocal。 通过将系统属性isThreadContextMapInheritable设置为true,上下文映射的内容将传递给子线程。 修改log4j2.xml中的pattern格式现在要在日志语句中打印以上标记,您需要在log4j2配置文件中修改转换模式。 <?xml version="1.0" encoding="UTF-8"?> <Configuration status="INFO"> <Appenders> <Console name="console" target="SYSTEM_OUT"> <PatternLayout pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] [%X{id}] [%X{ipAddress}] %c{1} - %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug" additivity="false"> <AppenderRef ref="console" /> </Root> </Loggers> </Configuration>单独使用%X可以包含地图的全部内容。 使用%X {key}来包含指定的密钥。使用%x包含堆栈的全部内容。 现在,当您运行上面的代码时–您将获得以下输出: [DEBUG] 2016-06-21 13:09:56.485 [main] [7cdd4cf0-2c26-4b81-b374-1adce3781499] [192.168.21.9] Log4j2HelloWorldExample - Debug Message Logged !! [INFO ] 2016-06-21 13:09:56.487 [main] [7cdd4cf0-2c26-4b81-b374-1adce3781499] [192.168.21.9] Log4j2HelloWorldExample - Info Message Logged !! [DEBUG] 2016-06-21 13:09:56.487 [main] [7cdd4cf0-2c26-4b81-b374-1adce3781499] [192.168.21.9] Log4j2HelloWorldExample - Another Debug Message !! [DEBUG] 2016-06-21 13:09:56.487 [main] [] [] Log4j2HelloWorldExample - Thread Context Cleaned up !! [DEBUG] 2016-06-21 13:09:56.487 [main] [] [] Log4j2HelloWorldExample - Log message with no context information !!如您所见,前三个日志语句添加了上下文信息-其他两个语句没有此类信息。
  • Java编程中在高规模分布式环境中生成唯一的ID

    Java编程中在高规模分布式环境中生成唯一的IDJava编程中在高规模分布式环境中生成唯一的ID
  • Spring data-mongodb ID自增长注解实现

    Spring data-mongodb ID自增长注解实现,mongodb ID自增长<h2>1.创建一个文档。类似一个序列的作用</h2> <pre> <code class="language-java">package com.leftso.autoid; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Field; /** * 系统自增长表id存放表 * * @author xq * */ @Document(collection = "sys_sequence") public class SequenceId { @Id private String id; @Field("seq_id") private long seqId; @Field("coll_name") private String collName; public String getId() { return id; } public void setId(String id) { this.id = id; } public long getSeqId() { return seqId; } public void setSeqId(long seqId) { this.seqId = seqId; } public String getCollName() { return collName; } public void setCollName(String collName) { this.collName = collName; } } </code></pre> <h2>2.创建一个自定义注解用于处理需要自增长的ID</h2> <pre> <code class="language-java">package com.leftso.autoid; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 自定义自增长ID注解 * * @author xq * */ @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.FIELD }) public @interface AutoValue { } </code></pre> <h2><br /> 3.重写新增的监听事件</h2> <span style="color:#27ae60"><strong>注意:各大网站可能会有相似的代码。以下部分和spring data mongodb版本有关。下面代码中重写的public void onBeforeConvert(final Object source)方法在1.8版本开始就废弃了,不过官方推荐: Please use onBeforeConvert(BeforeConvertEvent),以下则为1.8以后版本的使用方法</strong></span> <pre> <code class="language-java">package com.leftso.autoid; import java.lang.reflect.Field; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.FindAndModifyOptions; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener; import org.springframework.data.mongodb.core.mapping.event.BeforeSaveEvent; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; import org.springframework.stereotype.Component; import org.springframework.util.ReflectionUtils; @Component public class SaveEventListener extends AbstractMongoEventListener<Object> { @Autowired private MongoTemplate mongo; @Override public void onBeforeSave(BeforeSaveEvent<Object> event) { Object source = event.getSource(); if (source != null) { ReflectionUtils.doWithFields(source.getClass(), new ReflectionUtils.FieldCallback() { public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { ReflectionUtils.makeAccessible(field); // 如果字段添加了我们自定义的AutoValue注解 if (field.isAnnotationPresent(AutoValue.class) && field.get(source) instanceof Number && field.getLong(source) == 0) { // field.get(source) instanceof Number && // field.getLong(source)==0 // 判断注解的字段是否为number类型且值是否等于0.如果大于0说明有ID不需要生成ID // 设置自增ID field.set(source, getNextId(source.getClass().getSimpleName())); } } }); } } /** * 获取下一个自增ID * * @param collName * 集合(这里用类名,就唯一性来说最好还是存放长类名)名称 * @return 序列值 */ private Long getNextId(String collName) { Query query = new Query(Criteria.where("coll_name").is(collName)); Update update = new Update(); update.inc("seq_id", 1); FindAndModifyOptions options = new FindAndModifyOptions(); options.upsert(true); options.returnNew(true); SequenceId seq = mongo.findAndModify(query, update, options, SequenceId.class); return seq.getSeqId(); } } </code></pre> <h2><br /> 4.使用自定义注解完成ID自增长的实现</h2> <pre> <code class="language-java">package com.leftso.entity; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import com.leftso.autoid.AutoValue; @Document public class Student { @AutoValue @Id private long id; private String name; public Student(String name) { super(); this.name = name; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } </code></pre> <br />  
  • Spring Boot Mybatis Shiro 中出现事务不生效原因及解决办法

    出现@Transactional事务不生效原因shiro 的Realm 中注入了用到事务的service,例如下面的​ /** * 自定义权限认证器 * 自定义实现Realm,实现自定义获取登录信息进行登录鉴权和获取权限信息进行权限鉴权出现@Transactional事务不生效原因shiro 的Realm 中注入了用到事务的service,例如下面的​ /** * 自定义权限认证器 * 自定义实现Realm,实现自定义获取登录信息进行登录鉴权和获取权限信息进行权限鉴权 */ public class UserRealm extends AuthorizingRealm {    //超管账号    @Value("${super.user}")    String su;            @Autowired    SystemUserService systemUserService; ​      @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {       // TODO CODE ...        return info;   } ​    /***     * 登录鉴定(就是鉴定用户是否登录)     * @param authenticationToken     * @return     * @throws AuthenticationException     */    @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {       // TODO CODE ...        return info;   } } ​按上方代码使用,SystemUserService 这个service中所有的事务都将不会生效。原因细节首先我们在项目整合Shiro的时候通过ShiroConfig做了一些配置,其中一项包括Shiro的授权认证器MemberAuthorizingRealm。在UserRealm中我们通过@Autowired注入了本篇的主角SystemUserService。Spring启动的时候,配置相关的都是优先初始化的,在初始化UserRealm的时候发现需要注入一个SystemUserService对象,容器里肯定是没有的,那么就提前将其初始化了。此时如果在MemberService还有通过@Autowired注入的其他依赖,那么会一并初始化,依赖中要是还有依赖会继续递归初始化,这样下来会导致一系列的实例都是没有被代理的。但是这时候Spring中创建代理的处理器是还没有的,导致SystemUserService的BeanPostProcessor中没有AbstractAutoProxyCreator这个对象,后面整个BeanPostProcessor列表执行的时候没有为其创建代理。Spring中的数据库事务都是需要代理支持的,所以MemberService中不能开启事务。解决办法方法一(推荐):在Realm中注入的service上面添加@Lazy注解/** * 自定义权限认证器 * 自定义实现Realm,实现自定义获取登录信息进行登录鉴权和获取权限信息进行权限鉴权 */ public class UserRealm extends AuthorizingRealm {    //超管账号    @Value("${super.user}")    String su;        @Lazy    @Autowired    SystemUserService systemUserService; ​      @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {       // TODO CODE ...        return info;   } ​    /***     * 登录鉴定(就是鉴定用户是否登录)     * @param authenticationToken     * @return     * @throws AuthenticationException     */    @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {       // TODO CODE ...        return info;   } }方法二:单独创建一个service直接和mapper打交道,然后注入到Realm中方法三:通过spring application getBean获取 service
  • Spring Boot 2.0 使用Maven git-commit-id插件

    Spring Boot 2.0 使用Maven git-commit-id插件Spring Boot 2.0 使用Maven git-commit-id插件
  • PowerDesigner教程 PowerDesigner设置MySQL自增长ID教程

    PowerDesigner配置MySQL数据库ID自增长教程PowerDesigner配置MySQL数据库ID自增长教程。PowerDesigner如何配置ID自增长?下面开始讲解1.确认当前选择的数据库(当然是选择MySQL啦)在PowerDesigner的菜单中选择database->Change Current DBMS...在打开的菜单中选择MySQL5.02.双击需要设置自增长ID的表头在打开的PowerDesigner表对话框中选择Cloumns这个tab页,也就是创建表字段的tab界面。点击Customize Cloumns and Filter,具体位置在哪里呢?看下面的图吧:​3.选中identity在步骤二弹出的PowerDesigner对话框中滚动下拉条找到identity并点击鼠标将其√上。如图:​勾上后点击ok按钮关闭对话框。4.Physical Options设置 在表的tab中找到Physical Options,点击切换该该tab界面。左边有一列的选择列表,找到auto_increment=(%d)点击选中并点击tab中间三个按钮中的 >>按钮将其放入右边的列表中。具体操作如图:​这里下面还可以设置自增长的启始值。5.设置字段的identity属性 表tab切换到columns tab,这时候会发现字段后面多了一个I的选择框,将鼠标放到I的顶部表头看到I代表的identity。这时候需要使用自增长的字段勾选I的选择框即可。如图:​6.PowerDesigner自增长sql预览 ​
  • zTree实现打开页面时异步加载数据及选中项ID提交到后台

    zTree实现打开页面时异步加载数据及选中项ID提交到后台1.页面 <pre> <code class="language-html"><!DOCTYPE html> <HTML> <HEAD> <TITLE> ZTREE DEMO </TITLE> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" href="demoStyle/demo.css" type="text/css"> <link rel="stylesheet" href="zTreeStyle/zTreeStyle.css" type="text/css"> <script type="text/javascript" src="ztreeJs/jquery-1.4.4.min.js"></script> <script type="text/javascript" src="ztreeJs/jquery.ztree.all.min.js"></script> </HEAD> <BODY> <div style="margin-left: 5%"> <article class="page-container"> <div class="row cl"> <label class="form-label col-xs-3 col-sm-3"><span class="c-red">*</span>角色名称:</label> <div class="formControls col-xs-6 col-sm-6"> <input type="hidden" name="roleId" value="111" id="roleId"/> <input type="text" class="input-text" value="测试" id="roleName" name="roleName"> </div> </div> <div class="row cl"> <label class="form-label col-xs-3 col-sm-3">权限列表:</label> <div class="formControls col-xs-6 col-sm-6"> <!-- 权限代码 zTree--> <div class="content_wrap"> <div class="zTreeDemoBackground left"> <ul id="treeDemo" class="ztree"></ul> </div> </div> </div> </div> <div class="row cl"> <div class="col-xs-3 col-sm-3 col-xs-offset-3 col-sm-offset-3"> <button type="button" class="btn btn-success radius sbm""> <i class="icon-ok"></i> 确定 </button> <button type="button" class="btn btn-success radius reset"> <i class="icon-ok"></i> 取消 </button> </div> </div> </article> </div> </BODY> </HTML></code></pre> <br /> 2.js <pre> <code class="language-java">//假设我们做的是为某个角色设置菜单权限,并且新增和修改权限用的一个页面 $(function() { var roleId=$("#roleId").val(); onLoadZTree(roleId); }); var setting = { check : { enable : true }, data : { simpleData : { enable : true, idKey : "id", pIdKey : "pId", rootPId : "" } } }; var treeNodes; function onLoadZTree(roleId) { $.ajax({ type:'post',//请求方式:post dataType : 'json',//数据传输格式:json url:'/sysRoleMenu/menuTreeAjax',//获取角色菜单URL地址 data:{"sysRoleId":roleId}, async:false,//是否异步 cache : false,//是否使用缓存 error:function(errorMsg){ //请求失败处理函数 alert('亲,请求失败!'); }, success:function(data){ if(data.errCode == 'ok'){ treeNodes = data.data;//把后台封装好的简单Json格式赋给treeNodes }else{ alert('亲,初始化角色菜单失败'); } } }); //这里我们假设返回的数据是: var treeNodes =[ { id:1, pId:0, name:"父节点1", open:true, checked:true}, { id:11, pId:1, name:"父节点11", checked:true}, { id:111, pId:11, name:"叶子节点111", checked:true}, { id:112, pId:11, name:"叶子节点112", checked:true}, { id:113, pId:11, name:"叶子节点113", checked:true}, { id:114, pId:11, name:"叶子节点114", checked:true}, { id:12, pId:1, name:"父节点12"}, { id:121, pId:12, name:"叶子节点121"}, { id:122, pId:12, name:"叶子节点122"}, { id:123, pId:12, name:"叶子节点123"}, { id:124, pId:12, name:"叶子节点124"}, { id:13, pId:1, name:"父节点13", isParent:true}, { id:2, pId:0, name:"父节点2"}, { id:21, pId:2, name:"父节点21", open:true}, { id:211, pId:21, name:"叶子节点211"}, { id:212, pId:21, name:"叶子节点212"}, { id:213, pId:21, name:"叶子节点213"}, { id:214, pId:21, name:"叶子节点214"}, { id:22, pId:2, name:"父节点22"}, { id:221, pId:22, name:"叶子节点221"}, { id:222, pId:22, name:"叶子节点222"}, { id:223, pId:22, name:"叶子节点223"}, { id:224, pId:22, name:"叶子节点224"}, { id:23, pId:2, name:"父节点23"}, { id:231, pId:23, name:"叶子节点231"}, { id:232, pId:23, name:"叶子节点232"}, { id:233, pId:23, name:"叶子节点233"}, { id:234, pId:23, name:"叶子节点234"}, { id:3, pId:0, name:"父节点3", isParent:true} ]; var t = $("#treeDemo"); t = $.fn.zTree.init(t, setting, treeNodes) }; //组装被选中的菜单为jsonArray格式 function onCheck() { var roleId = $("#roleId").val(); var roleName = $("#roleName").val(); var treeObj = $.fn.zTree.getZTreeObj("treeDemo"); var nodes = treeObj.getCheckedNodes(true);//获取被选中的节点 var jsonArr = "["; for (var i = 0; i < nodes.length; i++) { jsonArr += "{"; jsonArr += "\"roleId\":\""+roleId+"\","; jsonArr += "\"roleName\":\""+roleName+"\","; jsonArr += "\"menuId\":\""+nodes[i].id+"\","; jsonArr += "\"menuName\":\""+nodes[i].name+"\""; jsonArr += "}" jsonArr += ',' } jsonArr = jsonArr.substring(0, jsonArr.length - 1); jsonArr += "]"; return jsonArr; }; $(function() { $(".sbm").click(function(){ var roleId= $("#roleId").val(); var sysRoleMenuStr = onCheck(); $.ajax({ type:'post',//请求方式:post dataType : 'json',//数据传输格式:json url:'/sysRoleMenu/createSysRoleMenu', data:{"sysRoleId":roleId,"sysRoleMenuStr":sysRoleMenuStr}, async:false,//是否异步 cache : false,//是否使用缓存 error:function(errorMsg){ alert("亲分配权限菜单成功"); //成功之后你需要做什么操作都在这里写 }, success:function(data){ if(data.errCode == 'ok'){ alert("亲分配权限菜单出错"); }else{ alert("亲分配权限菜单出错"); } } }); } }); }); </code></pre> 3.控制层 <pre> <code class="language-java">@Controller @RequestMapping(value = "/sysRoleMenu") public class SysRoleMenuController{ /** * 初始化菜单树列表 * * @param model * @param sysRoleId * @return */ @ResponseBody @RequestMapping("/menuTreeAjax") public BaseResult initMenuTreeList(Model model, String sysRoleId) { BaseResult baseResult = new BaseResult(); try { List<SysMenuTreeVo> MenuTreeList = sysRoleMenuService.getSysMenuTreeVo(sysRoleId); baseResult = new BaseResult(ResultCode.AJAX_OK, MenuTreeList, "数据加载成功"); } catch (Exception e) { baseResult = new BaseResult(ResultCode.AJAX_Err, "", e.getMessage()); return baseResult; } return baseResult; } /** * 创建角色菜单权限 * * @param model * @param sysRoleId * @param sysRoleMenuStr * @return */ @ResponseBody @RequestMapping("/createSysRoleMenu") public BaseResult createSysRoleMenu(Model model, String sysRoleId, String sysRoleMenuStr) { // 解析数据 List<SysRoleMenu> sysRoleMenuList = changeSysRoleMenuList(sysRoleMenuStr); BaseResult baseResult = new BaseResult(); try { sysRoleMenuService.createSysRoleMenu(sysRoleId, sysRoleMenuList);//这个方法我采用的是先删除角色下面的所有菜单权限,然后再执行的新增,这样新增修改就只用一个页面 baseResult = new BaseResult(ResultCode.AJAX_OK, "", "创建成功"); } catch (Exception e) { baseResult = new BaseResult(ResultCode.AJAX_Err, "", e.getMessage()); log.error("SysRoleMenuController类createSysRoleMenu方法,创建菜单权限出错!", e); return baseResult; } return baseResult; } /** * 解析菜单jsonArray数据 * * @param sysRoleMenuStr * @return * @throws LoadRecordException */ public List<SysRoleMenu> changeSysRoleMenuList(String sysRoleMenuStr) throws LoadRecordException { List<SysRoleMenu> sysRoleMenus = null; if (StringUtil.isBlank(sysRoleMenuStr)) { return sysRoleMenus; } try { sysRoleMenus = new ArrayList<SysRoleMenu>(); JSONArray jsonArray = JSON.parseArray(sysRoleMenuStr); for (Object object : jsonArray) { SysRoleMenu sysRoleMenu = new SysRoleMenu(); JSONObject jsonObject = JSON.parseObject(object.toString()); String roleId = jsonObject.getString("roleId"); String roleName = jsonObject.getString("roleName"); String menuId = jsonObject.getString("menuId"); String menuName = jsonObject.getString("menuName"); sysRoleMenu.setRoleId(roleId); sysRoleMenu.setRoleName(roleName); sysRoleMenu.setMenuId(menuId); sysRoleMenu.setMenuName(menuName); sysRoleMenus.add(sysRoleMenu); } } catch (Exception e) { log.error("解析菜单数据出错,class:SysRoleMenuController;method:changeProductSaleRegionList;exception:Exception", e); throw new LoadRecordException("解析菜单数据错误,请确定你的格式:" + e.getMessage(), e); } return sysRoleMenus; } }</code></pre> 4.前台需要的封装对象 <pre> <code class="language-java">public class SysMenuTreeVo { // 菜单主键ID private String id; // 上级菜单 private String pId; // 菜单名称 private String name; // 是否展开 private Boolean open = Boolean.FALSE; // 是否选中 private Boolean checked = Boolean.FALSE; public SysMenuTreeVo() { } public SysMenuTreeVo(SysMenu sysMenu, Boolean checked, Boolean open) { if (sysMenu != null) { this.id = sysMenu.getId(); if (StringUtil.isNotBlank(sysMenu.getParentId())) { this.pId = sysMenu.getParentId(); } else { this.pId = "0"; } this.name = sysMenu.getName(); } this.open = open; this.checked = checked; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getpId() { return pId; } public void setpId(String pId) { this.pId = pId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Boolean getOpen() { return open; } public void setOpen(Boolean open) { this.open = open; } public Boolean getChecked() { return checked; } public void setChecked(Boolean checked) { this.checked = checked; } @Override public String toString() { return "SysMenuTreeVo [id=" + id + ", pId=" + pId + ", name=" + name + ", open=" + open + ", checked=" + checked + "]"; }</code></pre> 5.页面展示效果<br /> <img alt="" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-07/8601236fd58f40269b72ca344c8008bd.png" /><br /> <br />  
  • nexus3 通过pom.xml配置上传jar包

    一、maven私服上传自建的jar之项目的pom.xml文件配置 <repositories>l;<--私服下载配置-->l; <repository>l; <id>l;repos</id>l; <name>l;Repository</nam一、maven私服上传自建的jar之项目的pom.xml文件配置 <repositories><--私服下载配置--> <repository> <id>repos</id> <name>Repository</name> <url>http://your.ip:port/repository/maven-public/</url> </repository> </repositories> <distributionManagement><!--私有库上传--> <repository> <id>test-my</id><!--仓库ID,必须与maven 的setting.xml配置文件中server配置xml那个ID一致--> <name>my private maven</name><!--仓库描述--> <url>http://your.ip:port/repository/maven-my/</url><!--上传的仓库地址--> </repository> </distributionManagement> 上方配置说明点注意:<id>test-my</id> 这里的ID必须与maven的配置文件setting.xml中的server配置密码节点的ID一致。上传私有库的id必须唯一,后续会用到url地址为nexus私服库的路径,可在nexus管理界面进行复制,很多人默认使用的http://192.168.1.221:8081/repository/maven-releases 或者http://192.168.1.221:8081/repository/maven-snapshots 但是我这里使用的是自己创建的maven-my库。具体情况请跟进你的需求来定。 二、maven私服上传自建的jar之本地maven setting.xml文件配置 用过maven的同学都知道,maven有个重要的配置文件setting.xml。默认情况下,windows操作系统该文件存放路径为C:\Users\用户名\.m2\setting.xml编辑setting.xml添加私有库的认证信息。​配置maven setting.xml 配置点在于: <servers> <server> <id>test-my</id> <username>my</username> <password>lw123456==</password> </server> </servers> 注意:id的值test-my需与项目中的上传私有库配置的id一致,否则会出现权限问题。注意:这里的用户my必须要有相应的仓库操作权限三、通过idea deploy上传jar到私服 idea打开maven项目,选择deploy​上传过程:​好了可以网页登录去nexus3看看上传的结果了​有啥问题评论区留言给我​
  • Spring Boot 事物回滚实验

    1.开启事物通过注解开启@EnableTransactionManagement 提示: Spring Boot  以Spring 5.0为基础的版本无需注解自动开启事物2.测试事物首先查询数据库中的表​默认表中有一条数据;2.1默认不用事1.开启事物通过注解开启@EnableTransactionManagement 提示: Spring Boot  以Spring 5.0为基础的版本无需注解自动开启事物2.测试事物首先查询数据库中的表​默认表中有一条数据;2.1默认不用事物首先是不开启,创建两个数据代码如下:public void test() { SystemMenu m1=new SystemMenu(); m1.setName("test2"); m1.setTerminal("00"); menuExtMapper.insertSelective(m1); SystemMenu m2=new SystemMenu(); m2.setId(1);//重复ID 数据库会报错 m2.setName("test3"); m2.setTerminal("00"); }执行上面的代码:​通过控制台我们可以看到已经输出了 主键冲突的异常,我们再看看数据库:​通过数据库查询可以看到,test2数据已经存入数据库,test3肯定就是失败了,同时证明了默认没开启事物,遇到错误并不会回滚。2.2通过注解@Transactional开启事物首先我们将数据库还原,删除掉test2数据,如下:​程序代码如下:@Transactional public void test() { SystemMenu m1=new SystemMenu(); m1.setName("test2"); m1.setTerminal("00"); menuExtMapper.insertSelective(m1); SystemMenu m2=new SystemMenu(); m2.setId(1);//重复ID 数据库会报错 m2.setName("test3"); m2.setTerminal("00"); menuExtMapper.insertSelective(m2); }执行上方代码:​从控制台看,同样输出了主键冲突的错误,我们再看看数据库中的数据:​从数据可以看到,并没有数据存入。这里也就证明了事物开启成功,遇到错误就会同一回滚保证了数据的一致性。提示:默认情况下,@Transactional注解只对RuntimeException及其子类异常有效。证明上方的观点,下面以代码示例:@Transactional public void test() throws Exception { SystemMenu m1=new SystemMenu(); m1.setName("test2"); m1.setTerminal("00"); menuExtMapper.insertSelective(m1); if (1==1){ throw new Exception("EEEEEE"); } SystemMenu m2=new SystemMenu(); m2.setId(1);//重复ID 数据库会报错 m2.setName("test3"); m2.setTerminal("00"); menuExtMapper.insertSelective(m2); }上方代码,在处理数据中间主动抛出了Exception异常,执行代码观察控制台以及数据库:​控制台​数据库通过上方我们可以看到,抛出Exception的情况下事物并没有生效,test2已经存入数据库中。提示:可以通过注解@Transactional中的rollbackFor 来指定事物遇到那些异常会启用,同样也可以通过noRollbackFor指定那些异常不会滚例如下方的配置事物遇到所有的Exception都会回滚@Transactional(rollbackFor = {Exception.class})2.3 启用事物的方法内部调用其他方法出现异常会回滚吗首先我们蒋数据库恢复如下:​编写测试代码如下:@Transactional(rollbackFor = {Exception.class}) public void test() throws Exception { SystemMenu m1=new SystemMenu(); m1.setName("test2"); m1.setTerminal("00"); menuExtMapper.insertSelective(m1); oo(); } public void oo(){ SystemMenu m2=new SystemMenu(); m2.setId(1); m2.setName("test2"); m2.setTerminal("00"); menuExtMapper.insertSelective(m2); }执行代码,观察控制台和数据库:​控制台​数据库通过上方实验,我们可以看到事物生效了。所以内部调用其他方法出现异常同样会触发事物提示:调用的方法需没有标注注解@Transactional,如果标注注解会有几种情况,后方说明。2.4 启用事物的方法内部调用其他启用事物的方法编写测试代码1: @Transactional(rollbackFor = {Exception.class}) public void test() throws Exception { oo(); SystemMenu m1=new SystemMenu(); m1.setId(1); m1.setName("test2"); m1.setTerminal("00"); menuExtMapper.insertSelective(m1); } @Transactional public void oo(){ SystemMenu m2=new SystemMenu(); m2.setName("test3"); m2.setTerminal("00"); menuExtMapper.insertSelective(m2); }执行测试代码并观察控制台和数据库:​控制台​数据库通过上方实验,我们可以知道默认情况下,@Transactional注解的方法调用@Transactional注解的方法也是可以事物统一回滚的。注意:调用的方法上指定的Exception范围必须包含被调用方抛出异常的范围,否则可能出现不一致上方还涉及到一个知识点,事物的传播级别,默认情况下事物的传播级别为"REQUIRED",即:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。所以上方两个方法的事物会被整合成一个事物处理。@Transactional注解也可以通过propagation 来指定传播级别,如下:@Transactional(propagation = Propagation.REQUIRED)事物传播的几个级别分别为:REQUIRED(@Transactional注解默认值): 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。SUPPORTS:前方法不需要事务上下文,但是如果存在当前事务的话,那么这个方法会在这个事务中运行。MANDATORY:该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常。不会主动开启一个事务。REQUIRES_NEW:前方法必须运行在它自己的事务中。一个新的事务将被启动,如果存在当前事务,在该方法执行期间,当前事务会被挂起(如果一个事务已经存在,则先将这个存在的事务挂起)。如果使用JTATransactionManager的话,则需要访问TransactionManager。NOT_SUPPORTED:该方法不应该运行在事务中,如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager。NEVER:表示当前方法不应该运行在事务上下文中,如果当前正有一个事务在运行,则会抛出异常。NESTED:如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与REQUIRED一样。嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。(未完待续)后续继续更新实验....
  • SQL 删除某字段重复行不使用临时表 适用Mysql/sqlserver等

    前言       作为开发人员,我们经常遇到必须处理数据库相关内容的情况; 通常,当客户端以excel工作表的形式向您发送其数据,并且在经过一些excel操作后将数据推送到数据库表时,便完成了该操作前言       作为开发人员,我们经常遇到必须处理数据库相关内容的情况; 通常,当客户端以excel工作表的形式向您发送其数据,并且在经过一些excel操作后将数据推送到数据库表时,便完成了该操作。 我也这么干过多次。       这种方法面临的一个非常普遍的问题是,它有时可能会导致重复行,因为发送的数据,主要来自人力资源和财务等部门,而人们对数据标准化技术并不充分的了解[:-)]。       本教程主要讲解怎么使用sql将某些重复字段的行删除,并且不使用临时表的方式。该方法测试过MySQL,sql server理论其他关系数据库通用的。实际案例我将使用Employee表,其中的列名称为id, name, department and email。以下是用于生成测试数据的SQL脚本: Create schema TestDB; CREATE TABLE EMPLOYEE (     ID INT,     NAME Varchar(100),     DEPARTMENT INT,     EMAIL Varchar(100) ); INSERT INTO EMPLOYEE VALUES (1,'Anish',101,'anish@leftso.com'); INSERT INTO EMPLOYEE VALUES (2,'Lokesh',102,'lokesh@leftso.com'); INSERT INTO EMPLOYEE VALUES (3,'Rakesh',103,'rakesh@leftso.com'); INSERT INTO EMPLOYEE VALUES (4,'Yogesh',104,'yogesh@leftso.com'); -- 下面的是重复数据 INSERT INTO EMPLOYEE VALUES (5,'Anish',101,'anish@leftso.com'); INSERT INTO EMPLOYEE VALUES (6,'Lokesh',102,'lokesh@leftso.com'); 查询表,数据如下图所示:​重复数据SQL删除解决办法DELETE e1 FROM EMPLOYEE e1, EMPLOYEE e2 WHERE e1.name = e2.name AND e1.id > e2.id;执行结果如下图:​上面的sql查询将删除name字段重复的行,只有name唯一且ID字段最低的那些唯一行将被保留。 例如,ID为5和6的行将被删除,而ID为1和2的行将被保留。处理后查询结果如下图:​如果要保留具有最新生成的ID值的行,则将where子句中的条件反转为e1.id <e2.id,如下所示:DELETE e1 FROM EMPLOYEE e1, EMPLOYEE e2 WHERE e1.name = e2.name AND e1.id > e2.id; 如果要比较多个字段并添加适当的where子句。注意:请始终首先对测试数据执行上述(或修改的)查询,以确保其产生预期的输出。