A Bukkit plugin provides a central ORM Manager. It have no reload issue from Bukkit's build-in ORM support.
- Centralized ORM: Manage your database connections through a central plugin, avoiding reload issues.
- Ebean Integration: Leverages the powerful Ebean ORM for easy database operations.
- Virtual Thread Support: Optionally use Java 21+ virtual threads for highly efficient I/O-bound tasks.
- Redis Integration: Includes a Redis wrapper for distributed caching and messaging.
- Serialization: Provides a simple serializer based on Gson with Bukkit objects and JSR310 support.
- Distributed L2 Cache: Implements a distributed cache layer on top of Redis.
- Put the SimpleORM plugin jar into your server's
/pluginsfolder. - Start your server. A configuration folder
/plugins/SimpleORMwill be created. - Configure your database in the
config.ymlfile. - SimpleORM will be available as a service for other plugins to use.
For a sample implementation, see the xKit project.
If you want to use this library in your own plugin. code your main class like this. See Ebean ORM
public class MyPlugin extends JavaPlugin {
@Override
public void onEnable() {
/*
* If you dont whan to use manager object, follow this
* code. NOT RECOMMEND.
*
* EbeanHandler handler = new EbeanHandler();
* handler.setDriver("com.mysql.jdbc.Driver");
* handler.setUrl("jdbc:mysql://localhost:3306/database");
* handler.setUserName("userName");
* handler.setPassword("password");
*
* Use manager object will gen and read config field automatic.
* and will store handler into a map, your can get it even
* your plugin reload.
*
*/
// EbeanManager manager = EbeanManager.DEFAULT;
EbeanManager manager = getServer().getServicesManager()
.getRegistration(EbeanManager.class)
.getProvider();
EbeanHandler handler = manager.getHandler(this);
if (!handler.isInitialize()) {
handler.define(MyClass.class);
handler.define(MyOther.class);
try {
handler.initialize();
} catch(Exception e) {
// Do what you want to do.
}
}
// This function will inject into Bukkit's build-in
// ORM support.
handler.reflect();
// This function will try to create not exists tables.
handler.install();
// Injected build-in method. Return initialized
// Ebean server.
EbeanServer server = this.getDatabase();
// EbeanServer server = handler.getServer();
// ...
}
public void function() {
MyClass my = getDatabase.find(MyClass.class)
.where()
.eq("name", "zmy")
.findUnique();
System.out.print(my.getName());
// ...
}
}Code your entity class like this. See More Example.
@Entity
@Table(name = "o_table")
public class MyClass {
@Id
private int id;
@Column
private String name;
// Put getter and setter.
}Configure field will create automatic in your plguin's default config file. Like this.
dataSource:
driver: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost/database
userName: username
password: password- A @ManyToOne field is lazy load!
- A @ManyToOne field is not support on sqlite platform!
import com.mengcraft.simpleorm.ORM
import com.mengcraft.simpleorm.RedisWrapper
RedisWrapper redisWrapper = ORM.globalRedisWrapper();
redisWrapper.open(redis -> {
redis.set("my_key", "my_value");
// more codes here
});
redisWrapper.subscribe("my_channel", message -> {
Foo foo = Foo.decode(message);
// codes here
});
redisWrapper.publish("my_channel", "my_message");If you want to enable sentinel mode, make sure master_name is a non-empty string, or make sure it is null. An example is shown below.
redis:
master_name: i_am_master
url: redis://host1:26379,host2:26379,host3:26379
max_conn: 20Simple serializer and deserializer based on Gson with ConfigurationSerializable, ScriptObjectMirror and JSR310 supported.
import com.google.common.base.Preconditions
import com.mengcraft.simpleorm.ORM
import org.bukkit.Bukkit
import org.bukkit.Location
Location loc = new Location(Bukkit.getWorld("world"), 0, 0, 0)
Map<String, Object> map = ORM.serialize(loc)
Location loc2 = ORM.deserialize(Location.class, map)
Preconditions.checkState(Objects.equals(loc, loc2))Schedule async task to specific async pool or primary thread.
import com.mengcraft.simpleorm.ORM;
import java.util.function.Supplier;
ORM.enqueue("pool_name", () -> "any_async_task")
.thenComposeAsync(obj -> {
// Codes here
})
ORM.sync(() -> "any_sync_task")
.thenAccept(s -> {
// Codes here
})
import com.mengcraft.simpleorm.ORM
import com.mengcraft.simpleorm.redis.SimpleCache
def static customCalculator(String key) {
"hello, " + key
}
def cache = ORM.globalRedisWrapper().openCache(SimpleCache.Options.builder()
.name("sample")
.calculator(this::customCalculator)
.clustered(true)
.expire(300)
.expire2(3600)
.build())
cache.get("key")
.thenAccept({
cache.set("key", it)
})
cache.expire("key")
if (cache.isCached("key2")) {
cache.expire2("key2")
}