最近文章

JPA批量更新多个id的实体对象

在 Spring Data JPA 中,可以使用 @Query 注解和 HQL 或者 SQL 语句来执行自定义的更新操作。如果要根据多个 ID 更新实体对象,可以使用 IN 关键字。基于HQL的示例以下是一个示例,假设我们有一个名为 User 的实体类,其中包含 id 和 name 属性。现在我们想要根据多个 ID 更新这些用户的姓名: @Repository public interface U
标签:

Spring Jpa问题:InvalidDataAccessApiUsageException: No EntityManager with actual transaction available for current thread

通过Spring Data JPA调用deleteByXXX接口,报错:org.springframework.dao.InvalidDataAccessApiUsageException: No EntityManager with actual transaction available for current thread - cannot reliably process 'remove'
标签:

JPA存储枚举类型的几种处理方式

存储枚举类型到数据库可以分为以下三种需求:以整型存储,这个一般是按枚举定义的次序排列,即枚举的ordinal。存储为枚举的名称自定义存储枚举的内容,如code等等。在JPA 2.0以及之前的版本,一般使用的是@Enumerated来转换枚举类型,支持按枚举的ordinal和枚举名称来存储,不支持自定义枚举内存存储。JPA2.1引入Converter,就可以按需要定义转换枚举类型的存储。一、使用@E
标签:

MongoDB速查手册

列出所有的数据库show dbs显示当前数据db创建或者切换数据库use mydb删除数据库db.dropDatabase()创建集合Collectiondb.createCollection('users')列出数据库所有集合show collections插入一行数据/文档db.posts.insert({ title: '标题1', body: '内容', category: '
标签:

JPA JSON字符串与List以及对象的转换

有时为了方便,我们会吧对象或者List以JSON字符串的形式存放在数据库中。使用JPA就可以通过@Converte的方式实现。JSON字符与对象的转换,我们比较常用的时jackson,maven依赖如下:<dependencies> <!--加入jackson库--> <dependency> <groupId>com.
标签:

解决Spring boot 2.5.5 Maven 报错:Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources) on project myproject: Input length = 1 -> [Help 1]

把项目升级到Spring boot 2.5.5,在编译原理的项目时报错:[INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ myproject ---[INFO] Using 'UTF-8' encoding to copy filtered resources.[INFO] Using 'UTF-8' e
标签:

R语言根据name删除dataframe的列

根据名字删除dataframe里的列,可以使用subset函数。分为两种方式使用:1、知道想保留的列,使用subset显示保留。df <- data.frame(a = 1:10, b = 2:11, c = 3:12)df <- subset(df, select = c(a, c))示例中保留了a和c列2、指定删除的列,如上面例子中,要删除a和c列,如下:df <- subs
标签:

Objective-C的异常处理

异常:当程序执行时,发生的某种特殊状况,打断了正常的运转流程。Objective-C 的异常处理语法与Java和C++类似。通过使用 NSException, NSError 以及自定义的异常处理类来处理这些异常。Objective-C 对异常的支持包括四个编译器指令: @try、@catch、@throw 以及 @finally。使用规则:如果这句或这部分代码有可能出现问题,就把它放在@try{
标签:

Maven设置项目JDK版本为1.8

导入一个项目到iDEAL,项目中使用到lambda表达式的地方都报错,提示jdk版本不对。想到的第一种解决方案就是修改iDEAL的配置,修改两处的设置,如下:File → Settings → Java Compiler → Target bytecode version 改为1.8File → Project Structure → Modules → Language level 改为 8-L
标签:

Spring Data Mongo插入包含点(.)的key报错:MappingException: Map key user.name contains dots but no replacement was configured!

使用Spring Data Mongo插入带有点符号(.)的键时,抛出MappingException异常。报错信息如下:org.springframework.data.mapping.model.MappingException: Map key user.name contains dots but no replacement was configured! Make sure map k

Spring Boot 禁用MongoDB数据库自动化配置(auto configuration)的方式

Spring Boot提供了两种方式来禁用自动化配置:注解方式以及配置文件(application.properties)方式。注解方式在@SpringBootApplication注解上添加exclude属性,把MongoAutoConfiguration和MongoDataAutoConfiguration排除即可如下:@SpringBootApplication(exclude = {Mon
标签:

R把dataframe里的NA值替换为0

在R里可以使用来把NA值替换为0:df[is.na(d)] <- 0 示例> m <- matrix(sample(c(NA, 1:10), 100, replace = TRUE), 10) > d <- as.data.fra
标签:

JPA批量更新多个id的实体对象

在 Spring Data JPA 中,可以使用 @Query 注解和 HQL 或者 SQL 语句来执行自定义的更新操作。如果要根据多个 ID 更新实体对象,可以使用 IN 关键字。

基于HQL的示例

以下是一个示例,假设我们有一个名为 User 的实体类,其中包含 id 和 name 属性。现在我们想要根据多个 ID 更新这些用户的姓名:


@Repository
public interface UserRepository extends JpaRepository<User, Long> {
   @Transactional
   @Modifying
   @Query("UPDATE User u SET u.name = :name WHERE u.id IN (:ids)")
   int updateUsersNameByIds(@Param("name") String name, @Param("ids") List<Long> ids);
}

示例中定义的更新方法 updateUsersNameByIds(),使用 @Query 注解设置更新操作的 HQL 语句,其中 :name:ids 是参数占位符。@Param 注解用于指定参数名称。

在 HQL 语句中,使用使用了 IN 关键字并传入了一个 List<Long> 类型的参数 ids,表示要更新的用户 ID 列表。

最后,使用 @Modifying@Transactional 注解分别标记该方法为更新操作和事务性操作。

使用该方法时,只需要传入要更新的用户姓名和 ID 列表即可:

基于Native方式SQL

将上面的示例改写为native的sql方式,可以在 @Query 注解中设置 nativeQuery=true 属性。
 

改后的示例:

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
   @Transactional
   @Modifying
   @Query(value = "UPDATE user SET name = :name WHERE id IN (:ids)", nativeQuery = true)
   int updateUsersNameByIds(@Param("name") String name, @Param("ids") List<Long> ids);
}

上面的代码中,我们使用了 value 属性指定了 Native SQL 语句,其中 :name :ids 是参数占位符,与 HQL 语句类似。同时设置了 nativeQuery = true 表示该语句是原生的 SQL 语句。

原生的SQL,UPDATE语句对应的是数据库表中的表名user,和字段名name,id;而在HQL中,对应的是实体名User和实体属性name,id。

 

 

Spring Jpa问题:InvalidDataAccessApiUsageException: No EntityManager with actual transaction available for current thread

发布于 2022.03.20 3分钟阅读 0 评论 5 推荐

    JPA问题集

    作者: GreatNN
  1. Spring Jpa问题:InvalidDataAccessApiUsageException: No EntityManager with actual transaction available for current thread Page 1

通过Spring Data JPA调用deleteByXXX接口,报错:

org.springframework.dao.InvalidDataAccessApiUsageException: No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call; nested exception is javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:403) ~[spring-orm-5.3.10.jar:5.3.10]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:235) ~[spring-orm-5.3.10.jar:5.3.10]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:551) ~[spring-orm-5.3.10.jar:5.3.10]

Spring Data JPA内部的EntityManager的PersistenceContextType默认为TRANSACTION,即需要事务的作用域中执行。

解决方法:

  1. 在执行的方法上添加@Transactional。
  2. Spring基于AOP的代理实现@Transactional,对于添加@Transactional的方法需要是public。

 

JPA存储枚举类型的几种处理方式

存储枚举类型到数据库可以分为以下三种需求:

  1. 以整型存储,这个一般是按枚举定义的次序排列,即枚举的ordinal
  2. 存储为枚举的名称
  3. 自定义存储枚举的内容,如code等等。

JPA 2.0以及之前的版本,一般使用的是@Enumerated来转换枚举类型,支持按枚举的ordinal和枚举名称来存储,不支持自定义枚举内存存储。

JPA2.1引入Converter,就可以按需要定义转换枚举类型的存储。

一、使用@Enumerated注解

先讲解JPA2.0以及之前版本的@Enumerated@EnumType实现存储ordinal和枚举名称的方式。

后面以User为示例:

@Entity
public class User {
    @Id
    private int id;

    private String name;

    // 构造函数, getters和setters方法
}

映射枚举类型为ordinal值

@Enumerated(EnumType.ORDINAL) 注释放在枚举字段上,JPA 将实体存储到数据库时,会使用 Enum.ordinal() 值。

没有添加@Enumerated,或者没有指定EnumType.ORDINAL,默认情况下,JPA也是使用Enum.ordinal() 值。

如给User添加Status枚举:

public enum Status {
    NORMAL, DISABLED;
}

添加后如下:

@Entity
public class User{
    @Id
    private int id;

    private String name;

    @Enumerated(EnumType.ORDINAL)
    private Status status;
}

存储枚举ordinal缺点

以枚举的ordinal存储,有一个很大的缺点就是:当需要修改枚举时,就会出现映射的问题。 如果在中间添加一个新值或重新排列枚举的顺序,将破坏现有的数据的ordinal值。 这些问题可能很难发现,也很难修复,必须更新所有数据库记录。

映射枚举类型为名称

使用 @Enumerated(EnumType.STRING) 注释枚举字段,JPA 将在存储实体时使用 Enum.name() 值。

给User添加Role枚举:

public enum Role {
    NORMAL,VIP,ADMIN;
}

添加后User:

@Entity
public class User{
    @Id
    private int id;

    private String name;

    @Enumerated(EnumType.ORDINAL)
    private Status status;

    @Enumerated(EnumType.STRING)
    private Role role;
}

缺点

以枚举名称存储在数据库需要注意的问题是:尽量不要修改枚举的名称,否则需要同步更新相关记录。

二、使用@PostLoad@PrePersist Annotations

另一个选择是使用JPA的回调方法。在@PostLoad 和@PrePersist 事件中来回映射的枚举。 这个做法需要在实体上定义两个属性。 一个映射到数据库值,另一个添加@Transient 字段为枚举值。业务逻辑代码使用transient枚举属性。 

如在User中添加Priority枚举属性,映射逻辑中使用它的int值

public enum Priority {
    LOW(100), MEDIUM(200), HIGH(300);

    private int priority;

    private Priority(int priority) {
        this.priority = priority;
    }

    public int getPriority() {
        return priority;
    }

    public static Priority of(int priority) {
        return Stream.of(Priority.values())
                .filter(p -> p.getPriority() == priority)
                .findFirst()
                .orElseThrow(IllegalArgumentException::new);
    }
}

在User中使用如下:

@Entity
public class User {
    @Id
    private int id;

    private String name;

    @Enumerated(EnumType.ORDINAL)
    private Status status;

    @Enumerated(EnumType.STRING)
    private Role role;

    @Basic
    private int priorityValue;

    @Transient
    private Priority priority;

    @PostLoad
    void toPriorityTransient() {
        if (priorityValue > 0) {
            this.priority = Priority.of(priorityValue);
        }
    }

    @PrePersist
    void toPriorityPersistent() {
        if (priority != null) {
            this.priorityValue = priority.getPriority();
        }
    }
}

User中添加:

  1. @PostLoad注释的方法toPriorityTransient(),JPA加载实体时,用于把数据库的值映射为枚举类型。
  2. @PrePersist注释的方法toPriorityPersistent(),用于JPA保持实体时把priority的枚举类型转换为数值。

缺点

这样可以自定义保存的枚举值,但是缺点在代码上不是很优雅,一个字段需要有两个属性来表示。

三、使用JPA 2.1 @Converter注解

为了克服上述解决方案的局限性,JPA 2.1 版本引入了一个新的API,可用于将实体属性转换为数据库值,反之亦然。 我们需要做的就是创建一个实现 javax.persistence.AttributeConverter 的新类,并用@Converter 对其进行注解。

当然@Converter不仅用于枚举类型的转换,还可以用于其他类型的转换,这里是以枚举为例。

这里以上面的priority枚举为例,创建Priority的转换器。

@Converter(autoApply = true)
public class PriorityConverter implements AttributeConverter<Priority, Integer> {

    @Override
    public Integer convertToDatabaseColumn(Priority priority) {
        if (priority == null) {
            return null;
        }
        return priority.getPriority();
    }

    @Override
    public Priority convertToEntityAttribute(Integer priorityValue) {
        if (priorityValue == null) {
            return null;
        }

        return Priority.of(priorityValue);
    }
}

修改后的User即为:

@Entity
public class User {
    @Id
    private int id;

    private String name;

    @Enumerated(EnumType.ORDINAL)
    private Status status;

    @Enumerated(EnumType.STRING)
    private Role role;

    @Convert(converter = PriorityConverter .class)
    private Priority priority;
}

这样代码就相对使用@PostLoad和@PrePersist的方法要优雅,并且能实现自定义的灵活的转换。

四、总结

总结下:

  1. 如果只是简单的映射为枚举的ordinal或者名称,推荐使用@Enumerated注释。
  2. 要更灵活自定义的转换,推荐使用JPA2.1的@Converter
  3. 因为枚举的Ordinal映射,如果修改了枚举的次序,或者增删枚举值,可能会导致难以发现的问题,除非确定不会修改,否则不推荐使用。

 

 

MongoDB速查手册

列出所有的数据库

show dbs

显示当前数据

db

创建或者切换数据库

use mydb

删除数据库

db.dropDatabase()

创建集合Collection

db.createCollection('users')

列出数据库所有集合

show collections

插入一行数据/文档

db.posts.insert({
  title: '标题1',
  body: '内容',
  category: 'news',
  tags: ['新闻', '事件'],
  user: {
    name: '张三',
    status: 'author'
  },
  date: Date()
})

插入多行/文档

db.posts.insertMany([
  {
    title: 'Post Two',
    body: 'Body of post two',
    category: 'Technology',
    date: Date()
  },
  {
    title: 'Post Three',
    body: 'Body of post three',
    category: 'News',
    date: Date()
  },
  {
    title: 'Post Four',
    body: 'Body of post three',
    category: 'Entertainment',
    date: Date()
  }
])

获取所有文档

db.posts.find()

获取所有文档,并且美化输出格式

db.find().pretty()

根据字段查询文档

db.posts.find({ category: 'News' })

文档排序

# 升序
db.posts.find().sort({ title: 1 }).pretty()
# 降序
db.posts.find().sort({ title: -1 }).pretty()

统计文档数量

db.posts.find().count()
db.posts.find({ category: 'news' }).count()

限定文档查询行数

db.posts.find().limit(2).pretty()

链式查询,包括limit,排序

db.posts.find().limit(2).sort({ title: 1 }).pretty()

Foreach迭代

db.posts.find().forEach(function(doc) {
  print("Blog Post: " + doc.title)
})

查询一行数据

db.posts.findOne({ category: 'News' })

查询返回指定字段

db.posts.find({ title: 'Post One' }, {
  title: 1,
  author: 1
})

更新文档

db.posts.update({ title: 'Post Two' },
{
  title: 'Post Two',
  body: 'New body for post 2',
  date: Date()
},
{
  upsert: true
})

更改指定字段

db.posts.update({ title: 'Post Two' },
{
  $set: {
    body: 'Body for post 2',
    category: 'Technology'
  }
})

数字字段自增操作 ($inc)

db.posts.update({ title: 'Post Two' },
{
  $inc: {
    likes: 5
  }
})

重命名字段

db.posts.update({ title: 'Post Two' },
{
  $rename: {
    likes: 'views'
  }
})

删除文档

db.posts.remove({ title: 'Post Four' })

内嵌文档

db.posts.update({ title: 'Post One' },
{
  $set: {
    comments: [
      {
        body: 'Comment One',
        user: 'Mary Williams',
        date: Date()
      },
      {
        body: 'Comment Two',
        user: 'Harry White',
        date: Date()
      }
    ]
  }
})

查询数组里的元素 ($elemMatch)

db.posts.find({
  comments: {
     $elemMatch: {
       user: 'Mary Williams'
       }
    }
  }
)

添加索引

db.posts.createIndex({ title: 'text' })

文本检索

db.posts.find({
  $text: {
    $search: "\"Post O\""
    }
})

大于/小于查询

db.posts.find({ views: { $gt: 2 } })
db.posts.find({ views: { $gte: 7 } })
db.posts.find({ views: { $lt: 7 } })
db.posts.find({ views: { $lte: 7 } })

收藏备用

JPA JSON字符串与List以及对象的转换

有时为了方便,我们会吧对象或者List以JSON字符串的形式存放在数据库中。使用JPA就可以通过@Converte的方式实现。

JSON字符与对象的转换,我们比较常用的时jackson,maven依赖如下:

<dependencies>
     <!--加入jackson库-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.8.0</version>
    </dependency>
  </dependencies>

JSONObject字符串转换为对象

这里以Order和Metadata为例。

1、首先创建用于转换Metadata对象的转换器。

@Converter(autoApply = true)
public class JSONConverter implements AttributeConverter<Metadata, String> {
    private final static Logger LOGGER = LoggerFactory.getLogger(JSONConverter .class);
    private final static ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public String convertToDatabaseColumn(Metadata meta) {
        try {
            return objectMapper.writeValueAsString(meta);
        } catch (JsonProcessingException ex) {
            LOGGER.error("", ex);
            return null;
        }
    }

    @Override
    public Metadata convertToEntityAttribute(String dbData) {
        try {
            return objectMapper.readValue(dbData, Metadata.class);
        } catch (IOException ex) {
            LOGGER.error("", ex);
            return null;
        }
    }
}

代码实现了JPA转换器接口AttributeConverter,这个接口提供了两个方法:

  • convertToDatabaseColumn:用于把对象转换为数据库字段存储的值。
  • convertToEntityAttribute:用于把数据库里的字段存储的值转换为对象。

在convertToDatabaseColumn方法中,使用了Jackson的ObjectMapper的writeValuAsString,把对象转换为JSONObject的字符串。

在convertToEntityAttribute方法中,也是用了Jackson的ObjectMapperreadValue方法,把字符串转换为对象。

 

2、在Order对象中添加注解@Convert

@Entity
@Table(name = "order")
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Convert(converter = JSONConverter.class)
    private Metadata metadata;

    //…get 和set方法
}

JSONArray字符串转换为List

JSONArray与List之间的转换类似于对象的转换,但因为Jackson对List范类型的转换实现不同,所以在字符串转换List实现方式不同。

1、定义转换器

@Converter(autoApply = true)
public class OrderItemsJSONConverter implements AttributeConverter<List<OrderItem>, String> {

    private final static Logger LOGGER = LoggerFactory.getLogger(ChaptersJSONConverter.class);

    private final static ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public String convertToDatabaseColumn(List<OrderItem> meta) {
        try {
            return objectMapper.writeValueAsString(meta);
        } catch (JsonProcessingException ex) {
            LOGGER.error("", ex);
            return null;
        }
    }

    @Override
    public List<OrderItem> convertToEntityAttribute(String dbData) {
        try {
            if(dbData == null){  //如果dbData为null会导致转换报错,可以根据业务需求对null做处理
                return new ArrayList<>();
            }
            return objectMapper.readValue(dbData, new TypeReference<List<OrderItem>>(){});
        } catch (IOException ex) {
            LOGGER.error("", ex);
            return null;
        }
    }

}

在字符串转换List,objectMapper.readValue的类型时TypeReference,这个是与对象转换不同的地方。

2、Order的OrderItem列表添加@Convert注释

import javax.persistence.*;
import java.util.List;

@Entity
@Table(name = "order")
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Convert(converter = JSONConverter.class)
    private Metadata metadata;

    @Convert(converter = ItemsJSONArrayConverter.class)
    private List<OrderItem> item;

    //get set方法
}

解决Spring boot 2.5.5 Maven 报错:Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources) on project myproject: Input length = 1 -> [Help 1]

把项目升级到Spring boot 2.5.5,在编译原理的项目时报错:

[INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ myproject ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Using 'UTF-8' encoding to copy filtered properties files.
[INFO] Copying 3 resources
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.409 s
[INFO] Finished at: 2021-09-25T06:23:36+08:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources) on project myproject : Input length = 1 -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException


原因定位

原因是我们的*.properties文件使用了非UTF-8字符:

mail.fromPerson=�뾭�ʼ�

spring-boot-starter-parent配置的maven-resources-plugin,Spring Boot 默认使用 UTF-8,如前面的提示:

[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Using 'UTF-8' encoding to copy filtered properties files.

这是maven-resources-plugin:3.2.0的一个bug,在maven-resources-plugin:3.2.0之前的插件是能够兼容非UTF-8字符。spring boot 2.4升级到maven-resources-plugin:3.2.0,就出现了这个问题。

解决方法

方法一:把非UTF-8的字符改为UTF-8字符,或者删掉


方法二:在pom文件里降低maven-resources-plugin版本为3.1.0(推荐)

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
</plugin>

方法三:排除对含有非UTF-8的资源,包含properties文件过滤

在pom文件添加插件配置:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.2.0</version>
<!-- 在此添加被排除过滤的文件 -->
<configuration>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>properties</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>

参考:

https://github.com/spring-projects/spring-boot/issues/24346

https://stackoverflow.com/questions/65910112/maven-clean-install-failed-to-execute-goal-org-apache-maven-pluginsmaven-resou/65910205

R语言根据name删除dataframe的列

根据名字删除dataframe里的列,可以使用subset函数。分为两种方式使用:

1、知道想保留的列,使用subset显示保留。

df <- data.frame(a = 1:10, b = 2:11, c = 3:12)
df <- subset(df, select = c(a, c))

示例中保留了a和c列

2、指定删除的列,如上面例子中,要删除a和c列,如下:

df <- subset(df, select = -c(a, c))

Objective-C的异常处理

异常:当程序执行时,发生的某种特殊状况,打断了正常的运转流程。

  • Objective-C 的异常处理语法与Java和C++类似。通过使用 NSException, NSError 以及自定义的异常处理类来处理这些异常。
  • Objective-C 对异常的支持包括四个编译器指令: @try、@catch、@throw 以及 @finally。使用规则:
  • 如果这句或这部分代码有可能出现问题,就把它放在@try{}中.
  • @catch 捕获异常,出现了问题后,会执行到这里,然后你就可以对错误进行另外的处理,比如记录日志或者提醒用户哪错了。
  • @finally 无论是否会抛出异常,这个块中的代码都会执行。
  • @throw指令允许你抛出自己的异常。可以使用该指令抛出特定的异常。

异常分类

  1. 数组越界;
  2. 不能识别的方法选择器;
  3. 野指针调用:指针指向销毁的对象;

示例:

@try {
// @try 块中写有可能出错的代码段
NSArray *array = [NSArray array];
[array objectAtIndex:1]; //数组越界
} @catch (NSException *exception) {
// @catch 块内处理异常代码
NSLog(@"捕获到异常:%@%@",exception.name, exception.reason);
} @finally {
//可选项,不管是否出现异常,都会执行此代码段
NSLog(@"始终执行的代码!");
}
NSLog(@"Hello, World!");

输出结果:

Demo[17328:3652315] 捕获到异常:NSRangeException*** -[__NSArray0 objectAtIndex:]: index 1 beyond bounds for empty NSArray
Demo[17328:3652315] 始终执行的代码!
Demo[17328:3652315] Hello, World!

Maven设置项目JDK版本为1.8

导入一个项目到iDEAL,项目中使用到lambda表达式的地方都报错,提示jdk版本不对。

想到的第一种解决方案就是修改iDEAL的配置,修改两处的设置,如下:

File → Settings → Java Compiler → Target bytecode version 改为1.8
File → Project Structure → Modules → Language level 改为 8-Lambdas,type annotations etc.

这样就可以了。后面想了想,是否可以通过maven来设置。

maven在pom.xml配置build添加maven-compiler-plugin插件,设置source为1.8即可,示例如下:

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>

通过在maven中设置jdk版本为1.8,这样在其他地方导入项目就不需要手动修改iDEAL了。

Spring Data Mongo插入包含点(.)的key报错:MappingException: Map key user.name contains dots but no replacement was configured!

使用Spring Data Mongo插入带有点符号(.)的键时,抛出MappingException异常。

报错信息如下:

org.springframework.data.mapping.model.MappingException: Map key user.name contains dots but no replacement was configured! Make sure map keys don't contain dots in the first place or configure an appropriate replacement!
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.potentiallyEscapeMapKey(MappingMongoConverter.java:711)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.prepareMapKey(MappingMongoConverter.java:693)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeMapInternal(MappingMongoConverter.java:660)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:387)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:361)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:84)
at org.springframework.data.mongodb.core.CustomMongoTemplate.toDbObject0(CustomMongoTemplate.java:780)
at org.springframework.data.mongodb.core.CustomMongoTemplate.doInsert(CustomMongoTemplate.java:762)
at org.springframework.data.mongodb.core.CustomMongoTemplate.insert(CustomMongoTemplate.java:707)

这个错误在异常信息里也是说明了,是因为mongo的键是不能包含点符号“.“,所以需要在插入包含点符号的键做转换。

在Spring Data Mongo里的MappingMongoConverter转换器提供了setMapKeyDotReplacement的方法,用于我们设置对键中包含点符号(.)做替换。

使用如下:

@Configuration
public class PrimaryMongoConfig {
@Bean
@Primary
@ConfigurationProperties(prefix="spring.data.mongodb")
public MongoProperties primaryMongoProperties() {
return new MongoProperties();
}
@Primary
@Bean
public MongoTemplate primaryMongoTemplate() throws Exception {
return new MongoTemplate(primaryFactory(), mappingMongoConverter());
}
@Bean
@Primary
public MongoDbFactory primaryFactory() throws Exception {
MongoProperties mongoProperties = primaryMongoProperties();
ServerAddress serverAddress = new ServerAddress(mongoProperties.getHost(), mongoProperties.getPort());
List<MongoCredential> mongoCredentialList = new ArrayList<>();
mongoCredentialList.add(MongoCredential.createCredential(mongoProperties.getUsername(),
mongoProperties.getAuthenticationDatabase(), mongoProperties.getPassword()));
return new SimpleMongoDbFactory(new MongoClient(serverAddress, mongoCredentialList), mongoProperties.getDatabase());
}
@Bean
public MappingMongoConverter mappingMongoConverter() throws Exception {
DbRefResolver dbRefResolver = new DefaultDbRefResolver(primaryFactory());
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, new MongoMappingContext());
converter.setMapKeyDotReplacement("_");
converter.afterPropertiesSet();
return converter;
}
}

在mappingMongoConverter方法里调用了converter.setMapKeyDotReplacement("__"),把“.”转换为“\__”。这样查到Mongo里的包含“.”的键就会使用“__”代替。

Spring Boot 禁用MongoDB数据库自动化配置(auto configuration)的方式

Spring Boot提供了两种方式来禁用自动化配置:注解方式以及配置文件(application.properties)方式。

注解方式

在@SpringBootApplication注解上添加exclude属性,把MongoAutoConfiguration和MongoDataAutoConfiguration排除即可如下:

@SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})

配置文件(application.properties)

除了使用注解方式,也可以在application.properties上添加spring.autoconfigure.exclude排除项,如下:

spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration

对于Spring boot其他自动配置的项目也可以采取类似的做法。

R把dataframe里的NA值替换为0

在R里可以使用来把NA值替换为0:

df[is.na(d)] <- 0

示例

> m <- matrix(sample(c(NA, 1:10), 100, replace = TRUE), 10)
> d <- as.data.frame(m)
   V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1   4  3 NA  3  7  6  6 10  6   5
2   9  8  9  5 10 NA  2  1  7   2
3   1  1  6  3  6 NA  1  4  1   6
4  NA  4 NA  7 10  2 NA  4  1   8
5   1  2  4 NA  2  6  2  6  7   4
6  NA  3 NA NA 10  2  1 10  8   4
7   4  4  9 10  9  8  9  4 10  NA
8   5  8  3  2  1  4  5  9  4   7
9   3  9 10  1  9  9 10  5  3   3
10  4  2  2  5 NA  9  7  2  5   5

> d[is.na(d)] <- 0

> d
   V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1   4  3  0  3  7  6  6 10  6   5
2   9  8  9  5 10  0  2  1  7   2
3   1  1  6  3  6  0  1  4  1   6
4   0  4  0  7 10  2  0  4  1   8
5   1  2  4  0  2  6  2  6  7   4
6   0  3  0  0 10  2  1 10  8   4
7   4  4  9 10  9  8  9  4 10   0
8   5  8  3  2  1  4  5  9  4   7
9   3  9 10  1  9  9 10  5  3   3
10  4  2  2  5  0  9  7  2  5   5