["insert into post (title, id) values (?, ?)"], Params:[(First post,1)]
["select manytoonet0_.id as id1_0_0_, manytoonet0_.title as title2_0_0_ from post manytoonet0_ where manytoonet0_.id=?"], Params:[(1)]
["insert into post_comment (post_id, review, id) values (?, ?, ?)"], Params:[(1,My first review,1)]
["select manytoonet0_.id as id1_1_0_, manytoonet0_.post_id as post_id3_1_0_, manytoonet0_.review as review2_1_0_ from post_comment manytoonet0_ where manytoonet0_.id=?"], Params:[(1)]
["update post_comment set post_id=?, review=? where id=?"], Params:[(NULL(BIGINT),My first review,1)]
["select manytoonet0_.id as id1_1_0_, manytoonet0_.post_id as post_id3_1_0_, manytoonet0_.review as review2_1_0_ from post_comment manytoonet0_ where manytoonet0_.id=?"], Params:[(1)]
["delete from post_comment where id=?"], Params:[(1)]
["insert into post (title, id) values (?, ?)"], Params:[(First post,1)]
["insert into post_comment (post_id, review, id) values (?, ?, ?)"], Params:[(1,My first review,1)]
["insert into post_comment (post_id, review, id) values (?, ?, ?)"], Params:[(1,My second review,2)]
["insert into post_comment (post_id, review, id) values (?, ?, ?)"], Params:[(1,My third review,3)]
["select manytoonet0_.id as id1_1_0_, manytoonet0_.post_id as post_id3_1_0_, manytoonet0_.review as review2_1_0_ from post_comment manytoonet0_ where manytoonet0_.id=?"], Params:[(2)]
["delete from post_comment where id=?"], Params:[(2)]
["select manytoonet0_.id as id1_1_, manytoonet0_.post_id as post_id3_1_, manytoonet0_.review as review2_1_ from post_comment manytoonet0_ where manytoonet0_.post_id=?"], Params:[(1)]
import javax.persistence.*;
import java.io.Serializable;
import java.util.Objects;
@Entity(name = "Department")
@Table(name = "departments")
public class Department implements Serializable {
@Id
@GeneratedValue
private Long id = 0L;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
private Institute institute;
public Department(){}
public void setId(Long id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setInstitute(Institute institute) {
this.institute = institute;
}
public Department(String name){
this.name = name;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public Institute getInstitute() {
return institute;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Department)) return false;
Department that = (Department) o;
return name.equals(that.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}
DepartmentDAO
import com.jpa.demo.model.bidirectional.Department;
import com.jpa.demo.model.bidirectional.Institute;
import com.jpa.demo.utils.JPAUtil;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
public class DepartmentDAO {
private EntityManagerFactory entityManagerFactory = JPAUtil.getEntityManagerFactory();
public void saveDepartment(Long instituteId) {
EntityManager entityManager = null;
Long id = null;
try {
entityManager = this.entityManagerFactory.createEntityManager();
EntityTransaction tx = entityManager.getTransaction();
tx.begin();
Institute institute = entityManager.find(Institute.class, instituteId);
Department department = new Department("深圳研究所-第一部门");
department.setInstitute(institute);
entityManager.persist(department);
tx.commit();
} finally {
entityManager.close();
}
}
}
测试代码
@Test
public void testSaveDepartment() {
Institute institute = new Institute("深圳研究所");
institute.addDepartment(
new Department("深圳研究所1部")
);
InstituteDAO dao = new InstituteDAO();
dao.save(institute);
Long instituteId = institute.getId();
DepartmentDAO departmentDAO = new DepartmentDAO();
departmentDAO.saveDepartment(instituteId);
}
日志信息
Hibernate:
select
institute0_.id as id1_1_0_,
institute0_.name as name2_1_0_
from
institutes institute0_
where
institute0_.id=?
Hibernate:
call next value for hibernate_sequence
Hibernate:
insert
into
departments
(institute_id, name, id)
values
(?, ?, ?)
可以看出,我在保存部门信息的时候,同时还查询除了研究所信息,这里可以优化为直接保存部门信息。
只需要修改一行代码
Institute institute = entityManager.getReference(Institute.class, instituteId);
@Test
public void testQueryDepartment() {
Institute institute = new Institute("深圳研究所");
institute.addDepartment(
new Department("深圳研究所1部")
);
InstituteDAO dao = new InstituteDAO();
dao.save(institute);
Long instituteId = institute.getId();
DepartmentDAO departmentDAO = new DepartmentDAO();
Department department = departmentDAO.saveDepartment(instituteId);
Long departmentId = department.getId();
departmentDAO.queryDepartment(departmentId);
}
日志信息:
Hibernate:
select
department0_.id as id1_0_0_,
department0_.institute_id as institut3_0_0_,
department0_.name as name2_0_0_
from
departments department0_
where
department0_.id=?
Hibernate:
select
institute0_.id as id1_1_0_,
institute0_.name as name2_1_0_
from
institutes institute0_
where
institute0_.id=?
Hibernate:
select
department0_.id as id1_0_0_,
institute1_.id as id1_1_1_,
department0_.institute_id as institut3_0_0_,
department0_.name as name2_0_0_,
institute1_.name as name2_1_1_
from
departments department0_
inner join
institutes institute1_
on department0_.institute_id=institute1_.id
where
department0_.id=?
require("@fatso83/mini-mocha").install();
const { expect } = require('chai');
class BTreeNode {
constructor(isLeaf){
//是否属于叶子节点
this.isLeaf = isLeaf;
//节点用于存储具体数据的数组,且数据从前到后有顺序
this.values = [];
//存储节点对应的分支,或者子节点
this.children = [];
//存储节点所在的树节点
this.tree = null;
//节点对应的父节点
this.parent = null;
}
/**
* 获取节点存储数据的长度
*/
get n() {
return this.values.length;
}
/**
* 在某个节点增加一个值
*/
addValue(value) {
if(!value) {
return;
}
let pos = 0;
while(pos < this.n && this.values[pos] < value) {
pos++;
}
return this.values.splice(pos,0,value);
}
removeValue(pos) {
if (pos >= this.n) {
return null;
}
return this.values.splice(pos, 1)[0];
}
/**
* 在指定位置添加一个子节点
*/
addChild(node, pos) {
this.children.splice(pos,0,node);
node.parent = this;
}
/**
* 删除指定位置的节点
*/
removeChild(pos) {
return this.children.splice(pos,1)[0];
}
}
describe('BTreeNode test',()=>{
it('BTreeNode init test',()=>{
let bTreeNode = new BTreeNode(false);
expect(bTreeNode.isLeaf).to.equal(false);
expect(bTreeNode.n).to.equal(0);
expect(bTreeNode.children.length).to.equal(0);
expect(bTreeNode.tree).to.equal(null);
expect(bTreeNode.parent).to.equal(null);
});
it('BTreeNode addValue test',()=>{
let bTreeNode = new BTreeNode(false);
bTreeNode.addValue(5);
bTreeNode.addValue(8);
bTreeNode.addValue(2);
expect(bTreeNode.n).to.equal(3);
const values = bTreeNode.values;
expect(values.join('')).to.equal('258')
});
it('BTreeNode removeValue test',()=>{
let bTreeNode = new BTreeNode(false);
bTreeNode.addValue(3);
bTreeNode.addValue(9);
bTreeNode.addValue(7);
bTreeNode.addValue(6);
expect(bTreeNode.n).to.equal(4);
const values = bTreeNode.values;
expect(values.join('')).to.equal('3679');
bTreeNode.removeValue(2);
expect(bTreeNode.n).to.equal(3);
const values1 = bTreeNode.values;
expect(values1.join('')).to.equal('369');
})
});
class BTree {
constructor(order){
this.order = order;
this.root = null;
}
/**
* Search a value in the Tree and return the node. O(log N)
* @param {number} value
* @returns {BTreeNode}
*/
searchValue(node,value) {
if (node.values.includes(value)) {
return node;
}
if (node.leaf) {
return null;
}
let child = 0;
while(child <= node.n && node.values[child]< parseInt(value,10)) {
child++;
}
return this.searchValue(node.children[child],value);
}
/**
* Insert a new value in the tree O(log N)
* @param {number} value
*/
insert(value) {
const actual = this.root;
if (actual.n === 2 * this.order - 1) {
// Create a new node to become the root
// Append the old root to the new one
const temp = new BTreeNode(false);
temp.tree = this;
this.root = temp;
temp.addChild(actual, 0);
this.split(actual, temp, 1);
this.insertNonFull(temp, parseInt(value));
} else {
this.insertNonFull(actual, parseInt(value));
}
}
/**
* Insert a value in a not-full node. O(1)
* @param {BTreeNode} node
* @param {number} value
*/
insertNonFull(node, value) {
if (node.leaf) {
node.addValue(value);
return;
}
let temp = node.n;
//找到需要插入的位置
while(temp >1 && value < node.values[temp-1]) {
temp = temp-1;
}
if(node.children[temp].n === (this.order * 2 -1) ) {
this.split(node.children[temp], node, temp + 1);
if (value > node.values[temp]) {
temp = temp + 1;
}
}
this.insertNonFull(node.children[temp], value);
}
/**
* Divide child node from parent into parent.values[pos-1] and parent.values[pos]
* O(1)
* @param {BTreeNode} child
* @param {BTreeNode} parent
* @param {number} pos
*/
split(child, parent, pos) {
const newChild = new BTreeNode(child.leaf);
newChild.tree = this.root.tree;
// Create a new child
// Pass values from the old child to the new
for (let k = 1; k < this.order; k++) {
newChild.addValue(child.removeValue(this.order));
}
// Trasspass child nodes from the old child to the new
if (!child.leaf) {
for (let k = 1; k <= this.order; k++) {
newChild.addChild(child.deleteChild(this.order), k - 1);
}
}
// Add new child to the parent
parent.addChild(newChild, pos);
// Pass value to parent
parent.addValue(child.removeValue(this.order - 1));
parent.leaf = false;
}
/**
* Deletes the value from the Tree. O(log N)
* @param {number} value
*/
delete(value) {
if (this.root.n === 1 && !this.root.leaf &&
this.root.children[0].n === this.order-1 && this.root.children[1].n === this.order -1) {
// Check if the root can shrink the tree into its childs
this.mergeNodes(this.root.children[1], this.root.children[0]);
this.root = this.root.children[0];
}
// Start looking for the value to delete
this.deleteFromNode(this.root, parseInt(value, 10));
}
/**
* Delete a value from a node
* @param {BTreeNode} node
* @param {number} value
*/
deleteFromNode(node, value) {
const index = node.values.indexOf(value);
if (index >=0) {
// Value present in the node simple case1 叶子节点且数目也足够,直接删除
if (node.leaf && node.n > this.order - 1) {
// If the node is a leaf and has more than order-1 values, just delete it
node.removeValue(node.values.indexOf(value));
return true;
}
if(node.children[index].n > this.order-1 ||
node.children[index+1].n > this.order-1) {
// One of the immediate children has enough values to transfer
if (node.children[index].n > this.order - 1) {
// Replace the target value for the higher of left node.
// Then delete that value from the child
const predecessor = this.getMinMaxFromSubTree(node.children[index], 1);
node.values[index] = predecessor;
return this.deleteFromNode(node.children[index], predecessor);
}
const successor = this.getMinMaxFromSubTree(node.children[index+1], 0);
node.values[index] = successor;
return this.deleteFromNode(node.children[index+1], successor);
}
// Children has not enough values to transfer. Do a merge
this.mergeNodes(node.children[index + 1], node.children[index]);
return this.deleteFromNode(node.children[index], value);
}
// Value is not present in the node
if (node.leaf) {
// Value is not in the tree
return false;
}
// Value is not present in the node, search in the children
let nextNode = 0;
while (nextNode < node.n && node.values[nextNode] < value) {
nextNode++;
}
if (node.children[nextNode].n > this.order - 1) {
// Child node has enough values to continue
return this.deleteFromNode(node.children[nextNode], value);
}
// Child node has not enough values to continue
// Before visiting next node transfer a value or merge it with a brother
if ((nextNode > 0 && node.children[nextNode - 1].n > this.order - 1) ||
(nextNode < node.n && node.children[nextNode + 1].n > this.order - 1)) {
// One of the immediate children has enough values to transfer
if (nextNode > 0 && node.children[nextNode - 1].n > this.order - 1) {
this.transferValue(node.children[nextNode - 1], node.children[nextNode]);
} else {
this.transferValue(node.children[nextNode + 1], node.children[nextNode]);
}
return this.deleteFromNode(node.children[nextNode], value);
}
// No immediate brother with enough values.
// Merge node with immediate one brother
this.mergeNodes(
nextNode > 0 ? node.children[nextNode - 1] : node.children[nextNode + 1],
node.children[nextNode]);
return this.deleteFromNode(node.children[nextNode], value);
}
/**
* Get the lower or higher value in a sub-tree. O(log N)
* @param {BTreeNode} node
* @param { 0 | 1 } max 1 for find max, 0 for min
* @returns {number}
*/
getMinMaxFromSubTree(node, max) {
while (!node.leaf) {
node = node.children[max ? node.n : 0];
}
return node.values[max ? node.n - 1 : 0];
}
/**
* Transfer one value from the origin to the target. O(1)
* @param {BTreeNode} origin
* @param {BTreeNode} target
*/
transferValue(origin, target) {
const indexo = origin.parent.children.indexOf(origin);
const indext = origin.parent.children.indexOf(target);
if (indexo < indext) {
target.addValue(target.parent.removeValue(indexo));
origin.parent.addValue(origin.removeValue(origin.n-1));
if (!origin.leaf) {
target.addChild(origin.deleteChild(origin.children.length-1), 0);
}
} else {
target.addValue(target.parent.removeValue(indext));
origin.parent.addValue(origin.removeValue(0));
if (!origin.leaf) {
target.addChild(origin.deleteChild(0), target.children.length);
}
}
}
/**
* Mix 2 nodes into one. O(1)
* @param {BTreeNode} origin
* @param {BTreeNode} target
*/
mergeNodes(origin, target) {
const indexo = origin.parent.children.indexOf(origin);
const indext = target.parent.children.indexOf(target);
target.addValue(target.parent.removeValue(Math.min(indexo, indext)));
for (let i = origin.n - 1; i >= 0; i--) {
target.addValue(origin.removeValue(i));
}
// Remove reference to origin node
target.parent.deleteChild(indexo);
// Transfer all the children from origin node to target
if (!origin.leaf) {
while (origin.children.length) {
if (indexo > indext) {
target.addChild(origin.deleteChild(0), target.children.length);
} else {
target.addChild(origin.deleteChild(origin.children.length - 1), 0);
}
}
}
}
}
require("@fatso83/mini-mocha").install();
const { expect } = require('chai');
class Node {
constructor(data) {
this.data = data;
this.nextElement = null;
}
}
class LinkedList {
constructor() {
this.head = null;
}
//Insertion At Head
insertAtHead(newData) {
let tempNode = new Node(newData);
tempNode.nextElement = this.head;
this.head = tempNode;
return this; //returning the updated list
}
isEmpty() {
return (this.head == null);
}
//function to print the linked list
printList() {
const arrStr = [];
if (this.isEmpty()) {
arrStr.push('Empty List');
console.log(arrStr.join(''));
return false;
} else {
let temp = this.head;
while (temp != null) {
arrStr.push(temp.data);
arrStr.push('->');
temp = temp.nextElement;
}
arrStr.push('null');
console.log(arrStr.join(''));
return true;
}
}
getHead() {
return this.head;
}
setHead(newHead) {
this.head = newHead;
return this;
}
getListStr() {
if (this.isEmpty()) {
console.log("Empty List");
return "null";
} else {
let st = "";
let temp = this.head
while (temp != null) {
st += (temp.data);
st += " -> ";
temp = temp.nextElement;
}
st += "null";
return st;
}
}
insertAtTail(newData) {
//Creating a new Node with data as newData
let node = new Node(newData);
//check for case when list is empty
if (this.isEmpty()) {
//Needs to Insert the new node at Head
this.head = node;
return this;
}
//Start from head
let currentNode = this.head;
//Iterate to the last element
while (currentNode.nextElement != null) {
currentNode = currentNode.nextElement;
}
//Make new node the nextElement of last node of list
currentNode.nextElement = node;
return this;
}
search(value) {
//Start from the first element
let currentNode = this.head;
//Traverse the list until you find the value or reach the end
while (currentNode != null) {
if (currentNode.data == value) {
return true; //value found
}
currentNode = currentNode.nextElement
}
return false; //value not found
}
deleteAtHead() {
//if list is empty, do nothing
if (this.isEmpty()) {
return this;
}
//Get the head and first element of the list
let firstElement = this.head;
//If list is not empty, link head to the nextElement of firstElement
this.head = firstElement.nextElement;
return this;
}
deleteVal(value) {
let deleted = null; //True or False
//Write code here
//if list is empty return false
if (this.isEmpty()) {
return false;
}
//else get pointer to head
let currentNode = this.head;
// if first node's is the node to be deleted, delete it and return true
if (currentNode.data == value) {
this.head = currentNode.nextElement;
return true;
}
// else traverse the list
while (currentNode.nextElement != null) {
// if a node whose next node has the value as data, is found, delete it from the list and return true
if (currentNode.nextElement.data == value) {
currentNode.nextElement = currentNode.nextElement.nextElement;
return true;
}
currentNode = currentNode.nextElement;
}
//else node was not found, return false
deleted = false;
return deleted;
}
deleteAtTail() {
// check for the case when linked list is empty
if (this.isEmpty()) {
return this;
}
//if linked list is not empty, get the pointer to first node
let firstNode = this.head;
//check for the corner case when linked list has only one element
if (firstNode.nextElement == null) {
this.deleteAtHead();
return this;
}
//otherwise traverse to reach second last node
while (firstNode.nextElement.nextElement != null) {
firstNode = firstNode.nextElement;
}
//since you have reached second last node, just update its nextElement pointer to point at null, skipping the last node
firstNode.nextElement = null;
return this;
}
}
//定义一个Graphs
class Graph {
constructor(vertices){
//存储顶点数目
this.vertices = vertices;
//Defining an array which can
//hold LinkedLists equal to the number of vertices in the graph
//存储顶点对应的边的邻接表
this.list = [];
for (let i = 0 ; i < this.vertices ;i++) {
const temp = new LinkedList();
this.list.push(temp);
}
}
printGraph() {
console.log(">>Adjacency List of Directed Graph<<");
var i;
for (i = 0; i < this.list.length; i++) {
console.log("|" + (i) + "| => ");
let temp = this.list[i].getHead();
while (temp != null) {
console.log("[" + (temp.data) + "] -> ");
temp = temp.nextElement;
}
console.log("end ");
}
}
addEdge(source,destination) {
if (source < this.vertices && destination < this.vertices)
this.list[source].insertAtHead(destination);
}
}
describe('LinkedList test',()=>{
it('LinkedList insertAtHead test',()=>{
const list = new LinkedList();
expect(list.head).to.equal(null);
list.insertAtHead(10);
expect(list.head.data).to.equal(10);
list.insertAtHead(20);
expect(list.head.data).to.equal(20);
});
it('LinkedList isEmpty test',()=>{
const list = new LinkedList();
expect(list.isEmpty()).to.equal(true);
list.insertAtHead(10);
expect(list.isEmpty()).to.equal(false);
});
it('LinkedList printList test',()=>{
const list = new LinkedList();
expect(list.printList()).to.equal(false);
list.insertAtHead(10).insertAtHead(20).insertAtHead(30);
expect(list.printList()).to.equal(true);
});
});
let g = new Graph(4);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 3);
g.addEdge(2, 3);
g.printGraph();
What happens with the pasted content and what is filtered out (note: in case of pasting the other important mechanism is the conversion. HTML elements and attributes which are not upcasted by any of the registered converters are filtered out before they even become model nodes, so the schema is not applied to them; the conversion will be covered later in this guide).
To which elements the heading feature can be applied (which blocks can be turned to headings and which elements are blocks in the first place).
Which elements can be wrapped with a block quote.
Whether the bold button is enabled when the selection is in a heading (and whether the text in this heading can be bolded).
Where the selection can be placed (which is — only in text nodes and on object elements).
>gradle -v
Welcome to Gradle 7.3.3!
Here are the highlights of this release:
- Easily declare new test suites in Java projects
- Support for Java 17
- Support for Scala 3
For more details see https://docs.gradle.org/7.3.3/release-notes.html
------------------------------------------------------------
Gradle 7.3.3
------------------------------------------------------------
Build time: 2021-12-22 12:37:54 UTC
Revision: 6f556c80f945dc54b50e0be633da6c62dbe8dc71
Kotlin: 1.5.31
Groovy: 3.0.9
Ant: Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM: 11.0.13 (Oracle Corporation 11.0.13+10-LTS-370)
OS: Windows 10 10.0 amd64
在 Spring Data JPA 中,可以使用 @Query 注解和 HQL 或者 SQL 语句来执行自定义的更新操作。如果要根据多个 ID 更新实体对象,可以使用 IN 关键字。
基于HQL的示例
以下是一个示例,假设我们有一个名为 User 的实体类,其中包含 id 和 name 属性。现在我们想要根据多个 ID 更新这些用户的姓名:
@RepositorypublicinterfaceUserRepositoryextendsJpaRepository<User, Long> {
@Transactional@Modifying@Query("UPDATE User u SET u.name = :name WHERE u.id IN (:ids)")intupdateUsersNameByIds(@Param("name") String name, @Param("ids") List<Long> ids);
}
@RepositorypublicinterfaceUserRepositoryextendsJpaRepository<User, Long> {
@Transactional@Modifying@Query(value = "UPDATE user SET name = :name WHERE id IN (:ids)", nativeQuery = true)intupdateUsersNameByIds(@Param("name") String name, @Param("ids") List<Long> ids);
}
const {Injector} =require('didi');
/*
* 定义一个Car组件,这个Car组件依赖于engine组件
*/functionCar(engine) {
this.start = function() {
engine.start();
};
}
/**
* 定义一个Engine组件,同时这个Engine组件依赖于power组件
*/functioncreatePetrolEngine(power) {
return {
start: function() {
console.log('Starting engine with ' + power + 'hp');
}
};
}
// define a (didi) Car module,定义一个CarModule,这个模块由三个组件构建// it declares available components by name and specifies how these are providedconst carModule = {
//请求Car组件的时候,依赖注入器会调用Car的构造函数来创建组件// asked for 'car', the injector will call new Car(...) to produce it'car': ['type', Car],
//请求Engine组件的时候,依赖注入器会调用工厂方法来创建组件// asked for 'engine', the injector will call createPetrolEngine(...) to produce it'engine': ['factory', createPetrolEngine],
//请求power组件,依赖注入器会通过复制一个value值来创建。// asked for 'power', the injector will give it number 1184'power': ['value', 1184] // probably Bugatti Veyron
};
// instantiate an injector with a set of (didi) modulesconst injector = newInjector([
carModule
]);
//使用依赖注入器来检索组件并调用组件的API // use the injector API to retrieve components
injector.get('car').start();
//使用依赖注入器的invoke函数来注入相应的组件 // ...or invoke a function, injecting the arguments
injector.invoke(function(car) {
console.log('started', car);
car.start();
});
classCustomEntryOptionPlugin {
// This is the standard way of creating plugins.// It's either this, or a simple function, but we're using this approach// in order to be on par with how most of the plugins are created.apply(compiler) {
// Recall that hooks offer us the possibility to intervene in the// bundling process.// With the help of the `entryOption` hook, we're adding the logic// that will basically mean the start of the bundling process. As in,// the `entryObject` argument will hold the `entry` object from the// configuration file and we'll be using it to set up the creation of// module trees.
compiler.hooks.entryOption.tap('CustomEntryOptionPlugin', entryObject => {
// The `EntryOption` class will handle the creation of a module tree.constEntryOption = class {
constructor (options) {
this.options = options;
};
// Since this is still a plugin, we're abiding by the standard.apply(compiler) {
// The `start` hook marks the start of the bundling process.// It will be called **after** `hooks.entryOption` is called.
compiler.hooks.start('EntryOption', ({ createModuleTree }) => {
// Creating new tree of modules, based on the configuration of this plugin.// The `options` contain the name of the entry(which essentially is the name of the chunk)// and the file name.// The `EntryDependency` encapsulates these options and also provides way to// create modules(because it maps to a `NormalModuleFactory`, which produces `NormalModule`s).// After calling `createModuleTree`, the source code of the file will be found,// then a module instance will be created and then webpack will get its AST, which // will be further used in the bundling process.createModuleTree(newEntryDependency(this.options));
});
};
};
// For each item in the `entryObject` we're preparing// the creation of a module tree. Remember that each// module tree is independent of others.// The `entryObject` could be something like this: `{ a: './a.js' }`for (const name in entryObject) {
const fileName = entryObject[name];
// We're fundamentally saying: `ok webpack, when the bundling process starts,// be ready to create a module tree for this entry`.newEntryOption({ name, fileName }).apply(compiler);
};
});
}
};
// The way we're adding logic to the existing webpack hooks// is by using the `tap` method, which has this signature:// `tap(string, callback)`// where `string` is mainly for debugging purposes, indicating// the source where the custom logic has been added from.// The `callback`'s argument depend on the hook on which we're adding custom functionality.classUnderstandingModuleGraphPlugin {
apply(compiler) {
const className = this.constructor.name;
// Onto the `compilation` object: it is where most of the *state* of// the bundling process is kept. It contains information such as the module graph,// the chunk graph, the created chunks, the created modules, the generated assets// and much more.
compiler.hooks.compilation.tap(className, (compilation) => {
// The `finishModules` is called after *all* the modules(including// their dependencies and the dependencies' dependencies and so forth)// have been built.
compilation.hooks.finishModules.tap(className, (modules) => {
// `modules` is the set which contains all the built modules.// These are simple `NormalModule` instances. Once again, a `NormalModule`// is produced by the `NormalModuleFactory`.// console.log(modules);// Retrieving the **module map**(Map<Module, ModuleGraphModule>).// It contains all the information we need in order to traverse the graph.const {
moduleGraph: { _moduleMap: moduleMap },
} = compilation;
// Let's traverse the module graph in a DFS fashion.constdfs = () => {
// Recall that the root module of the `ModuleGraph` is the// *null module*.const root = null;
const visited = newMap();
consttraverse = (crtNode) => {
if (visited.get(crtNode)) {
return;
}
visited.set(crtNode, true);
console.log(
crtNode?.resource ? path.basename(crtNode?.resource) : 'ROOT'
);
// Getting the associated `ModuleGraphModule`, which only has some extra// properties besides a `NormalModule` that we can use to traverse the graph further.const correspondingGraphModule = moduleMap.get(crtNode);
// A `Connection`'s `originModule` is the where the arrow starts// and a `Connection`'s `module` is there the arrow ends.// So, the `module` of a `Connection` is a child node.// Here you can find more about the graph's connection: https://github.com/webpack/webpack/blob/main/lib/ModuleGraphConnection.js#L53.// `correspondingGraphModule.outgoingConnections` is either a Set or undefined(in case the node has no children).// We're using `new Set` because a module can be reference the same module through multiple connections.// For instance, an `import foo from 'file.js'` will result in 2 connections: one for a simple import// and one for the `foo` default specifier. This is an implementation detail which you shouldn't worry about.const children = newSet(
Array.from(
correspondingGraphModule.outgoingConnections || [],
(c) => c.module
)
);
for (const c of children) {
traverse(c);
}
};
// Starting the traversal.traverse(root);
};
dfs();
});
});
}
}
const path = require('path');
// We're printing this way in order to highlight the parent-child// relationships between `ChunkGroup`s.constprintWithLeftPadding = (message, paddingLength) => console.log(message.padStart(message.length + paddingLength));
classUnderstandingChunkGraphPlugin {
apply (compiler) {
const className = this.constructor.name;
compiler.hooks.compilation.tap(className, compilation => {
// The `afterChunks` hook is called after the `ChunkGraph` has been built.
compilation.hooks.afterChunks.tap(className, chunks => {
// `chunks` is a set of all created chunks. The chunks are added into// this set based on the order in which they are created.// console.log(chunks);// As we've said earlier in the article, the `compilation` object// contains the state of the bundling process. Here we can also find// all the `ChunkGroup`s(including the `Entrypoint` instances) that have been created.// console.log(compilation.chunkGroups);// An `EntryPoint` is a type of `ChunkGroup` which is created for each// item in the `entry` object. In our current example, there are 2.// So, in order to traverse the `ChunkGraph`, we will have to start// from the `EntryPoints`, which are stored in the `compilation` object.// More about the `entrypoints` map(<string, Entrypoint>): https://github.com/webpack/webpack/blob/main/lib/Compilation.js#L956-L957const { entrypoints } = compilation;
// More about the `chunkMap`(<Chunk, ChunkGraphChunk>): https://github.com/webpack/webpack/blob/main/lib/ChunkGraph.js#L226-L227const { chunkGraph: { _chunks: chunkMap } } = compilation;
constprintChunkGroupsInformation = (chunkGroup, paddingLength) => {
printWithLeftPadding(`Current ChunkGroup's name: ${chunkGroup.name};`, paddingLength);
printWithLeftPadding(`Is current ChunkGroup an EntryPoint? - ${chunkGroup.constructor.name === 'Entrypoint'}`, paddingLength);
// `chunkGroup.chunks` - a `ChunkGroup` can contain one or mode chunks.const allModulesInChunkGroup = chunkGroup.chunks
.flatMap(c => {
// Using the information stored in the `ChunkGraph`// in order to get the modules contained by a single chunk.const associatedGraphChunk = chunkMap.get(c);
// This includes the *entry modules* as well.// Using the spread operator because `.modules` is a Set in this case.return [...associatedGraphChunk.modules];
})
// The resource of a module is an absolute path and// we're only interested in the file name associated with// our module.
.map(module => path.basename(module.resource));
printWithLeftPadding(`The modules that belong to this chunk group: ${allModulesInChunkGroup.join(', ')}`, paddingLength);
console.log('\n');
// A `ChunkGroup` can have children `ChunkGroup`s.
[...chunkGroup._children].forEach(childChunkGroup =>printChunkGroupsInformation(childChunkGroup, paddingLength + 3));
};
// Traversing the `ChunkGraph` in a DFS manner.for (const [entryPointName, entryPoint] of entrypoints) {
printChunkGroupsInformation(entryPoint, 0);
}
});
});
}
};
这是您应该看到的输出:
Current ChunkGroup's name: foo;
Is current ChunkGroup an EntryPoint? - true
The modules that belong to this chunk group: a.js, b.js, a1.js, b1.js
Current ChunkGroup's name: bar;
Is current ChunkGroup an EntryPoint? - true
The modules that belong to this chunk group: c.js, common.js
Current ChunkGroup's name: c1;
Is current ChunkGroup an EntryPoint? - false
The modules that belong to this chunk group: c1.js
Current ChunkGroup's name: c2;
Is current ChunkGroup an EntryPoint? - false
The modules that belong to this chunk group: c2.js
在本文中,我们会解释 JPA persistence.xml 配置文件的用途,以及如何使用可用的 XML 标记或属性设置 Java Persistence 应用程序。
虽然 Spring 应用程序可以在不需要 XML JPA 配置文件的情况下进行引导,但理解每个配置选项的含义仍然很重要,因为 Spring 在构建 Java PersistenceLocalContainerEntityManagerFactoryBean 或 Hibernate-specific LocalSessionFactoryBean 时还提供了另一种方法。
<?xml version="1.0" encoding="UTF-8"?><persistence version="2.2"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"><persistence-unit
name="HypersistenceOptimizer"
transaction-type="JTA"><description>
Hypersistence Optimizer is a dynamic analyzing tool that can scan
your JPA and Hibernate application and provide you tips about the
changes you need to make to entity mappings, configurations, queries,
and Persistence Context actions to speed up your data access layer.
</description><provider>org.hibernate.jpa.HibernatePersistenceProvider</provider><jta-data-source>java:global/jdbc/default</jta-data-source><properties><property
name="hibernate.transaction.jta.platform"
value="SunOne"
/></properties></persistence-unit></persistence>
持久化标记<persistence>是根 XML 元素,它定义了 JPA 版本2.2和用于验证 persistence.xml 配置文件的 XML 模式。
<properties><property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/><property name="hibernate.connection.driver_class" value="org.h2.Driver"/><!-- H2 is running in pure in Memory db mode, data1.txt will be lost as soon as connection is closed --><property name="hibernate.connection.url" value="jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE"/><property name="hibernate.connection.username" value="sa"/><property name="hibernate.connection.pool_size" value="5"/><property name="hibernate.show_sql" value="true"/><property name="hibernate.format_sql" value="true"/><property name="hibernate.hbm2ddl.auto" value="update"/><property name="org.hibernate.type.descriptor.sql.BasicBinder" value="true"/><property name="org.hibernate.type.descriptor.sql.BasicExtractor" value="true"/></properties>
body {
background: hsl(210deg, 30%, 12%);
color: hsl(0deg0%100%);
}
.wrapper {
display: flex;
gap: 8px;
}
.item {
height: 32px;
border: 2px solid hsl(210deg8%50%);
background: hsl(210deg15%20%);
}
.item.stretch {
/*
Because this item is empty, it
has a default hypothetical width
of 0px. This isn't realistic,
though; in a typical case,
there would be content in here!
And so we set a width of 300px
to simulate it containing stuff.
*/width: 300px;
flex-grow: 1;
border-radius: 16px;
}
.item.ball {
width: 32px;
/*
NOTE: We could prevent the circle
from squishing into an oval by
setting border-radius: 16px
instead. I'm using percentages
because it makes for a better
demo. But even with a pixel-based
radius, we still need
flex-shrink: 0 to prevent the
item from shrinking (give it a
shot and see the difference!).
*/border-radius: 50%;
}
<!DOCTYPE html><html><head><meta charset="UTF-8"/><title>Ribbons设计 - 实例</title><link rel="stylesheet" type="text/css" href="./ribbon.css" /></head><body><div class="ribbon"><!-- The left side --><div class="ribbon__side ribbon__side--l"></div><!-- The left triangle displayed below the content --><div class="ribbon__triangle ribbon__triangle--l"></div><!-- The right triangle displayed below the content --><div class="ribbon__triangle ribbon__triangle--r"></div><!-- The right side --><div class="ribbon__side ribbon__side--r"></div><!-- The content --><div class="ribbon__content"></div></div></body></html>
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function's scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.
这个定义记住关键一点,它是在运行时产生的,一定是在函数创建时刻才有闭包
function outer() {
let counter = 0;
function inner() {
counter++;
console.log(counter);
}
inner();
}
outer();
outer();
// 1 1
function outer() {
let counter = 0;
function inner() {
counter++;
console.log(counter);
}
return inner;
}
let fn = outer();
fn();
fn();
// 1 2
An Object that is associated with persistence context (hibernate session) are in Persistent state. Any changes made to objects in this state are automatically propagated to databases without manually invoking persist/merge/remove
teacher: Student{id=null, email='new_email@gmail.com'} is transient state
Hibernate:
call next value for hibernate_sequence
teacher: Student{id=1, email='new_email@gmail.com'} is persistent state
teacher: Student{id=1, email='updated_email@gmail.com'} has changed email
Hibernate:
insert
into
teachers(email, id)
values
(?, ?)
Hibernate:
update
teachers
set
email=?
where
id=?
teacher: Student{id=1, email='updated_email@gmail.com'} is detached state
Hibernate:
select
teacher0_.id as id1_0_0_,
teacher0_.email as email2_0_0_
from
teachers teacher0_
where
teacher0_.id=?
Persisted teacher: Student{id=1, email='updated_email@gmail.com'}
// In your applicationinterfaceFreeTradeAgreementService {
getFromProduct(productId: string): FreeTradeAgreement;
}
// In your infrastructureclassTranslatingFreeTradeAgreementServiceimplementsFreeTradeAgreementService {
constructor(private readonly adapter: FreeTradeAgreementAdapter) {
}
asyncgetFromProduct(productId: string): Promise<FreeTradeAgreement> {
// More complex situations could require multiple calls to separate services in order to// build the local conceptreturnawaitthis.adapter.getFreeTradeAgreement(productId);
}
}
/*
* This class prints the given message on console.
*/publicclassMessageUtil {
private String message;
//Constructor//@param message to be printedpublicMessageUtil(String message){
this.message = message;
}
// prints the messagepublic String printMessage(){
System.out.println(message);
return message;
}
// add "Hi!" to the messagepublic String salutationMessage(){
message = "Hi!" + message;
System.out.println(message);
return message;
}
}