有必要让 MySQL Cluster 启动并运行。为简单起见,组成集群的所有节点(进程)将与应用程序一起在同一物理主机上运行。
这些是正在使用的 MySQL 集群配置文件:
配置.ini:
[ndbd default]noofreplicas=2
datadir=/home/billy/mysql/my_cluster/data
[ndbd]
hostname=localhost
id=3
[ndbd]
hostname=localhost
id=4
[ndb_mgmd]
id = 1
hostname=localhost
datadir=/home/billy/mysql/my_cluster/data
[mysqld]
hostname=localhost
id=101
[api]
hostname=localhost
我的.cnf:
[mysqld]
ndbcluster
datadir=/home/billy/mysql/my_cluster/data
basedir=/usr/local/mysql
这侧重于 ClusterJ 而不是运行 MySQL Cluster;如果您是 MySQL 集群的新手,请在尝试之前参考运行一个简单的集群。
ClusterJ 需要被告知如何连接到我们的 MySQL Cluster 数据库;包括连接字符串(管理节点的地址/端口)、要使用的数据库、登录用户以及连接的属性,例如超时值。如果未定义这些参数,则 ClusterJ 将因运行时异常而失败。此信息表示图 3 中所示的“配置属性”。这些参数可以在应用程序代码中进行硬编码,但创建将由应用程序导入的 clusterj.properties 文件更易于维护。该文件应与您的应用程序源代码存储在同一目录中。
clusterj.properties:
com.mysql.clusterj.connectstring=localhost:1186
com.mysql.clusterj.database=clusterdb
com.mysql.clusterj.connect.retries=4
com.mysql.clusterj.connect.delay=5
com.mysql.clusterj.connect.verbose=1
com.mysql.clusterj.connect.timeout.before=30
com.mysql.clusterj.connect.timeout.after=20
com.mysql.clusterj.max.transactions=1024
由于 ClusterJ 不会自动创建表,下一步是创建“clusterdb”数据库(在 clusterj.properties 中引用)和“employee”表:
[dadaso@ubuntu14-lts-server ~]$ mysql -u root -h 127.0.0.1 -P 3306 -u root
mysql> create database clusterdb;use clusterdb;
mysql> CREATE TABLE employee (
-> id INT NOT NULL PRIMARY KEY,
-> first VARCHAR(64) DEFAULT NULL,
-> last VARCHAR(64) DEFAULT NULL,
-> municipality VARCHAR(64) DEFAULT NULL,
-> started VARCHAR(64) DEFAULT NULL,
-> ended VARCHAR(64) DEFAULT NULL,
-> department INT NOT NULL DEFAULT 1,
-> UNIQUE KEY idx_u_hash (first,last) USING HASH,
-> KEY idx_municipality (municipality)
-> ) ENGINE=NDBCLUSTER;
下一步是创建带注释的接口:
员工.java:
import com.mysql.clusterj.annotation.Column;
import com.mysql.clusterj.annotation.Index;
import com.mysql.clusterj.annotation.PersistenceCapable;
import com.mysql.clusterj.annotation.PrimaryKey;
@PersistenceCapable(table="employee")
@Index(name="idx_uhash")
public interface Employee {
@PrimaryKey
int getId();
void setId(int id);
String getFirst();
void setFirst(String first);
String getLast();
void setLast(String last);
@Column(name="municipality")
@Index(name="idx_municipality")
String getCity();
void setCity(String city);
String getStarted();
void setStarted(String date);
String getEnded();
void setEnded(String date);
Integer getDepartment();
void setDepartment(Integer department);
}
表的名称在注解@PersistenceCapable(table=”employee”) 中指定,然后employee 表中的每一列都在接口中定义了关联的getter 和setter 方法。默认情况下,接口中的属性名称与表中的列名称相同 - 通过在关联的 getter 方法之前显式包含 @Column(name=”municipality”) 注释来覆盖 City 属性的列名称. @PrimaryKey 注解用于标识关联列是表中主键的属性。ClusterJ 使用 @Index 注释知道数据库中索引的存在。
下一步是编写我们在此处逐块执行的应用程序代码;第一个只包含导入语句,然后加载上面定义的 clusterj.properties 的内容:
Main.java(第 1 部分):
import com.mysql.clusterj.ClusterJHelper;
import com.mysql.clusterj.SessionFactory;
import com.mysql.clusterj.Session;
import com.mysql.clusterj.Query;
import com.mysql.clusterj.query.QueryBuilder;
import com.mysql.clusterj.query.QueryDomainType;
import java.io.File;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.*;
import java.util.Properties;
import java.util.List;
public class Main {
public static void main (String[] args) throws java.io.FileNotFoundException,java.io.IOException {
// Load the properties from the clusterj.properties file
File propsFile = new File("clusterj.properties");
InputStream inStream = new FileInputStream(propsFile);
Properties props = new Properties();
props.load(inStream);
//Used later to get userinput
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
下一步是从 ClusterJHelper 类获取 SessionFactory 的句柄,然后使用该工厂创建会话(基于从 clusterj.properties 文件导入的属性。
Main.java(第 2 部分):
// 创建会话(连接数据库) SessionFactory factory = ClusterJHelper.getSessionFactory(props); 会话会话 = factory.getSession(); 现在我们有了一个会话,就可以实例化新的 Employee 对象,然后将它们持久化到数据库中。如果没有事务 begin() 或 commit() 语句,则涉及数据库的每个操作都被视为单独的事务。
Main.java(第 3 部分):
/
/ Create and initialise an Employee
Employee newEmployee = session.newInstance(Employee.class);
newEmployee.setId(988);
newEmployee.setFirst("John");
newEmployee.setLast("Jones");
newEmployee.setStarted("1 February 2009");
newEmployee.setDepartment(666);
// Write the Employee to the database
session.persist(newEmployee);
此时,将在“员工”表中添加一行。为了验证这一点,创建了一个新的 Employee 对象,并使用主键 (Id) 值 998 从“employee”表中读取数据:
Main.java(第 4 部分):
// Fetch the Employee from the database
Employee theEmployee = session.find(Employee.class, 988);
if (theEmployee == null)
{System.out.println("Could not find employee");}
else
{System.out.println ("ID: " + theEmployee.getId() + "; Name: " +
theEmployee.getFirst() + " " + theEmployee.getLast());
System.out.println ("Location: " + theEmployee.getCity());
System.out.println ("Department: " + theEmployee.getDepartment());
System.out.println ("Started: " + theEmployee.getStarted());
System.out.println ("Left: " + theEmployee.getEnded());
}
这是此时看到的输出:
ID: 988; Name: John Jones
Location: null
Department: 666
Started: 1 February 2009
Left: null
在我更改员工之前检查数据库 - 完成后点击返回 下一步是修改此数据,但尚未将其写回数据库:
Main.java(第 5 部分):
// Make some changes to the Employee & write back to the database
theEmployee.setDepartment(777);
theEmployee.setCity("London");
System.out.println("Check the database before I change the Employee -
hit return when you are done");
String ignore = br.readLine();
应用程序将在此时暂停,并让您有机会检查数据库以确认原始数据已作为新行添加但尚未写回更改:
mysql> select * from clusterdb.employee;
+-----+-------+-------+--------------+-----------------+-------+------------+
| id | first | last | municipality | started | ended | department |
+-----+-------+-------+--------------+-----------------+-------+------------+
| 988 | John | Jones | NULL | 1 February 2009 | NULL | 666 |
+-----+-------+-------+--------------+-----------------+-------+------------+
点击返回后,应用程序将继续并将更改写入表,使用自动事务执行更新。
Main.java(第 6 部分):
session.updatePersistent(theEmployee);
System.out.println("Check the change in the table before I bulk add
Employees - hit return when you are done");
ignore = br.readLine();
应用程序将再次暂停,以便我们现在可以检查更改是否已写回(持久)到数据库:
mysql> select * from clusterdb.employee;
+-----+-------+-------+--------------+-----------------+-------+------------+
| id | first | last | municipality | started | ended | department |
+-----+-------+-------+--------------+-----------------+-------+------------+
| 988 | John | Jones | London | 1 February 2009 | NULL | 777 |
+-----+-------+-------+--------------+-----------------+-------+------------+
然后应用程序继续创建并保留 100 名新员工。为了提高性能,使用单个事务来在运行 commit() 语句时立即将所有更改写入数据库:
Main.java(第 7 部分):
// Add 100 new Employees - all as part of a single transaction
newEmployee.setFirst("Billy");
newEmployee.setStarted("28 February 2009");
session.currentTransaction().begin();
for (int i=700;i<800;i++) {
newEmployee.setLast("No-Mates"+i);
newEmployee.setId(i+1000);
newEmployee.setDepartment(i);
session.persist(newEmployee);
}
session.currentTransaction().commit();
100 名新员工现在将被持久化到数据库中。下一步是创建并执行一个查询,该查询将使用 QueryBuilder 搜索数据库以查找部门 777 中的所有员工,并使用该查询构建一个 QueryDomain,将“部门”列与参数进行比较。创建后,department 参数设置为 777(随后可以使用不同的部门编号重复使用该查询)。然后应用程序运行查询并遍历并显示结果集中的每个员工:
Main.java(第 8 部分):
// Retrieve the set all of Employees in department 777
QueryBuilder builder = session.getQueryBuilder();
QueryDomainType<Employee> domain =
builder.createQueryDefinition(Employee.class);
domain.where(domain.get("department").equal(domain.param(
"department")));
Query<Employee> query = session.createQuery(domain);
query.setParameter("department",777);
List<Employee> results = query.getResultList();
for (Employee deptEmployee: results) {
System.out.println ("ID: " + deptEmployee.getId() + "; Name: " +
deptEmployee.getFirst() + " " + deptEmployee.getLast());
System.out.println ("Location: " + deptEmployee.getCity());
System.out.println ("Department: " + deptEmployee.getDepartment());
System.out.println ("Started: " + deptEmployee.getStarted());
System.out.println ("Left: " + deptEmployee.getEnded());
}
System.out.println("Last chance to check database before emptying table
- hit return when you are done");
ignore = br.readLine();
此时,应用程序将显示以下内容并提示用户允许其继续:
ID: 988; Name: John Jones
Location: London
Department: 777
Started: 1 February 2009
Left: null
ID: 1777; Name: Billy No-Mates777
Location: null
Department: 777
Started: 28 February 2009
Left: null
我们可以将该输出与对数据库执行的 SQL 查询进行比较:
mysql> select * from employee where department=777;
+------+-------+-------------+--------------+------------------+-------+------------+
| id | first | last | municipality | started | ended | department |
+------+-------+-------------+--------------+------------------+-------+------------+
| 988 | John | Jones | London | 1 February 2009 | NULL | 777 |
| 1777 | Billy | No-Mates777 | NULL | 28 February 2009 | NULL | 777 |
+------+-------+-------------+--------------+------------------+-------+------------+
最后,再次按下返回后,应用程序将删除所有员工:
Main.java(第 9 部分):
session.deletePersistentAll(Employee.class);
作为最后的检查,SQL 查询确认所有行都已从“employee”表中删除。
mysql> select * from employee;
Empty set (0.00 sec)