{"id":13765813,"url":"https://github.com/hellokaton/anima","last_synced_at":"2025-04-06T18:16:50.790Z","repository":{"id":57724918,"uuid":"124876411","full_name":"hellokaton/anima","owner":"hellokaton","description":"Minimal database operation library.","archived":false,"fork":false,"pushed_at":"2022-05-04T13:07:42.000Z","size":483,"stargazers_count":226,"open_issues_count":9,"forks_count":48,"subscribers_count":13,"default_branch":"master","last_synced_at":"2024-05-18T17:57:07.909Z","etag":null,"topics":["activerecord","database","java8","orm-framework","transaction"],"latest_commit_sha":null,"homepage":"https://github.com/biezhi/anima/wiki","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hellokaton.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-03-12T11:06:33.000Z","updated_at":"2024-05-14T07:24:58.000Z","dependencies_parsed_at":"2022-09-11T01:50:25.347Z","dependency_job_id":null,"html_url":"https://github.com/hellokaton/anima","commit_stats":null,"previous_names":["biezhi/anima"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hellokaton%2Fanima","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hellokaton%2Fanima/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hellokaton%2Fanima/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hellokaton%2Fanima/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hellokaton","download_url":"https://codeload.github.com/hellokaton/anima/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247411225,"owners_count":20934653,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activerecord","database","java8","orm-framework","transaction"],"created_at":"2024-08-03T16:00:46.478Z","updated_at":"2025-04-06T18:16:50.753Z","avatar_url":"https://github.com/hellokaton.png","language":"Java","readme":"# Anima\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://github.com/biezhi/anima/wiki\"\u003e\u003cimg src=\"screenshot/cover.png\" width=\"623\"/\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n`Anima` allows you to query database like `SQL` and `Stream`.\na simple DSL syntax, supports multiple databases, integrates well with Java8, \nsupports multiple relational mappings, and is a database manipulation tool.\n\n**[Document](https://github.com/biezhi/anima/wiki)**\n\n[![Travis Build](https://travis-ci.org/hellokaton/anima.svg?branch=master)](https://travis-ci.org/hellokaton/anima)\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/3abf98fb260340cea9808d169cc47d8b)](https://www.codacy.com/app/hellokaton/anima?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=hellokaton/anima\u0026amp;utm_campaign=Badge_Grade)\n[![](https://img.shields.io/maven-central/v/com.hellokaton/anima.svg)](https://mvnrepository.com/artifact/com.hellokaton/anima)\n[![codecov](https://codecov.io/gh/hellokaton/anima/branch/master/graph/badge.svg)](https://codecov.io/gh/hellokaton/anima) \n[![License](https://img.shields.io/badge/license-Apache2-blue.svg)](https://github.com/biezhi/anima/blob/master/LICENSE)\n[![Twitter URL](https://img.shields.io/twitter/url/https/twitter.com/hellokaton.svg?style=social\u0026label=Follow%20Twitter)](https://twitter.com/hellokaton)\n\n## Feature\n\n- Simple DSL \n- H2、MySQL、SQLite、PostgreSQL、Oracle、SqlServer \n- Paging support \n- Flexible configuration \n- Connection pool support\n- Support `LocalDate`、`LocalDateTime`\n- Support lambda expression\n- Relationship (`hasOne`、`hasMany`、`belongsTo`)\n- SQL performance statistics\n- Based Java8\n\n# Usage\n\n**Latest snapshot version**\n\n\u003e If you want to prioritize new features or some BUG fixes you can use it, you need to specify the snapshot repository in `pom.xml`\n\n```xml\n\u003crepository\u003e\n    \u003cid\u003esnapshots-repo\u003c/id\u003e\n    \u003curl\u003ehttps://oss.sonatype.org/content/repositories/snapshots\u003c/url\u003e\n    \u003creleases\u003e\n        \u003cenabled\u003efalse\u003c/enabled\u003e\n    \u003c/releases\u003e\n    \u003csnapshots\u003e\n        \u003cenabled\u003etrue\u003c/enabled\u003e\n    \u003c/snapshots\u003e\n\u003c/repository\u003e\n\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.hellokaton\u003c/groupId\u003e\n    \u003cartifactId\u003eanima\u003c/artifactId\u003e\n    \u003cversion\u003e0.3.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nHere's the `RELEASE` version.\n\n**As Gradle**\n\n```java\ncompile 'com.hellokaton:anima:0.3.1'\n```\n\n**As Maven**\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.hellokaton\u003c/groupId\u003e\n    \u003cartifactId\u003eanima\u003c/artifactId\u003e\n    \u003cversion\u003e0.3.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n\u003e 📒 Although `Anima` can also be used by adding a jar package, we do not recommend doing this.\n\n## Examples\n\n**Open Connection**\n\n```java\n// MySQL\nAnima.open(\"jdbc:mysql://127.0.0.1:3306/demo\", \"root\", \"123456\");\n\n// SQLite\nAnima.open(\"jdbc:sqlite:./demo.db\");\n\n// H2\nAnima.open(\"jdbc:h2:file:~/demo;FILE_LOCK=FS;PAGE_SIZE=1024;CACHE_SIZE=8192\", \"sa\", \"\");\n\n// DataSource\nDruidDataSource dataSource = new DruidDataSource();\ndataSource.setDriverClassName(\"com.mysql.jdbc.Driver\");\ndataSource.setUrl(blade.environment().getOrNull(\"jdbc.url\"));\ndataSource.setUsername(blade.environment().getOrNull(\"jdbc.username\"));\ndataSource.setPassword(blade.environment().getOrNull(\"jdbc.password\"));\nAnima.open(dataSource);\n```\n\n\u003e 📕 This operation only needs one time\n\n```java\npublic class User extends Model {\n    \n    private Integer id;\n    private String  userName;\n    private Integer age;\n    \n    public User() {\n    }\n    \n    public User(String userName, Integer age) {\n        this.userName = userName;\n        this.age = age;\n    }\n    \n}\n```\n\nTable Structure\n\n```sql\nCREATE TABLE `users` (\n  `id` IDENTITY PRIMARY KEY,\n  `user_name` varchar(50) NOT NULL,\n  `age` int(11)\n)\n```\n\n### Query\n\n```java\nlong count = select().from(User.class).count();\n// SELECT COUNT(*) FROM users\n\nlong count = select().from(User.class).where(\"age \u003e ?\", 15).isNotNull(\"user_name\").count();\n// SELECT COUNT(*) FROM users WHERE age \u003e ? AND user_name IS NOT NULL\n\nUser user = select().from(User.class).byId(2);\n// SELECT * FROM users WHERE id = ?\n\nList\u003cUser\u003e users = select().from(User.class).byIds(1, 2, 3);\n// SELECT * FROM users WHERE id IN (?, ?, ?)\n\nString name = select().bySQL(String.class, \"select user_name from users limit 1\").one();\n\nList\u003cString\u003e names = select().bySQL(String.class, \"select user_name from users limit ?\", 3);\n\nList\u003cUser\u003e users = select().from(User.class).all();\n// SELECT * FROM users\n\nList\u003cUser\u003e users = select().from(User.class).like(\"user_name\", \"%o%\").all();\n// SELECT * FROM users WHERE user_name LIKE ?\n```\n\n**Limit**\n\n```java\nList\u003cUser\u003e users = select().from(User.class).order(\"id desc\").limit(5);\n// SELECT * FROM users ORDER BY id desc\n```\n\n**Paging**\n\n```java\nPage\u003cUser\u003e userPage = select().from(User.class).order(\"id desc\").page(1, 3);\n// SELECT * FROM users ORDER BY id desc LIMIT ?, ?\n```\n\n**Map**\n\n```java\nselect().from(User.class).map(User::getUserName).limit(3).collect(Collectors.toList());\n```\n\n**Filter**\n\n```java\nselect().from(User.class).filter(u -\u003e u.getAge() \u003e 10).collect(Collectors.toList());\n```\n\n**Lambda**\n\n```java\nUser user = select().from(User.class).where(User::getUserName).eq(\"jack\").one();\n// SELECT * FROM users WHERE user_name = ?\n```\n\n```java\nList\u003cUser\u003e user = select().from(User.class)\n                .where(User::getUserName).notNull()\n                .and(User::getAge).gt(10)\n                .all();\n// SELECT * FROM users WHERE user_name IS NOT NULL AND age \u003e ?\n```\n\n```java\nselect().from(User.class).order(User::getId, OrderBy.DESC).order(User::getAge, OrderBy.ASC).all();\n// SELECT * FROM users ORDER BY  id DESC, age ASC\n```\n\n**Join**\n\n```java\n@Table(name = \"order_info\")\n@Data\npublic class OrderInfo extends Model {\n\n    private Long id;\n\n    private Integer uid;\n\n    @Column(name = \"productname\")\n    private String productName;\n\n    private LocalDateTime createTime;\n\n    @Ignore\n    private User user;\n    \n    @Ignore\n    private Address address;\n\n}\n```\n\n```java\n// HasOne\nOrderInfo orderInfo = select().from(OrderInfo.class)\n        .join(\n            Joins.with(Address.class).as(OrderInfo::getAddress)\n                 .on(OrderInfo::getId, Address::getOrderId)\n        ).byId(3);\n\norderInfo = select().from(OrderInfo.class)\n        .join(\n            Joins.with(Address.class).as(OrderInfo::getAddress)\n                 .on(OrderInfo::getId, Address::getOrderId)\n        )\n        .join(\n                Joins.with(User.class).as(OrderInfo::getUser)\n                        .on(OrderInfo::getUid, User::getId)\n        ).byId(3);\n\n// ManyToOne\norderInfo = select().from(OrderInfo.class)\n        .join(\n            Joins.with(User.class).as(OrderInfo::getUser)\n                 .on(OrderInfo::getUid, User::getId)\n        ).byId(3);\n\n// OneToMany\nUserDto userDto = select().from(UserDto.class).join(\n            Joins.with(OrderInfo.class).as(UserDto::getOrders)\n                 .on(UserDto::getId, OrderInfo::getUid)\n        ).byId(1);\n```\n\n### Insert\n\n```java\nInteger id = new User(\"biezhi\", 100).save().asInt();\n// INSERT INTO users(id,user_name,age) VALUES (?,?,?)\n```\n\nor\n\n```java\nAnima.save(new User(\"jack\", 100));\n```\n\n**Batch Save**\n\n```java\nList\u003cUser\u003e users = new ArrayList\u003c\u003e();\nusers.add(new User(\"user1\", 10));\nusers.add(new User(\"user2\", 11));\nusers.add(new User(\"user3\", 12));\nAnima.saveBatch(users);\n```\n\n\u003e 📘 This operation will begin a transaction and rollback when there is a transaction that is unsuccessful.\n\n### Update\n\n```java\nint result  = update().from(User.class).set(\"user_name\", newName).where(\"id\", 1).execute();\n// UPDATE users SET username = ? WHERE id = ?\n```\n\nor\n\n```java\nint result = update().from(User.class).set(\"user_name\", newName).where(\"id\", 1).execute();\n// UPDATE users SET user_name = ? WHERE id = ?\n```\n\nor\n\n```java\nUser user = new User();\nuser.setId(1);\nuser.setUserName(\"jack\");\nuser.update();\n// UPDATE users SET user_name = ? WHERE id = ?\n```\n\n```java\nupdate().from(User.class).set(User::getUserName, \"base64\").updateById(2);\n```\n\n```java\nupdate().from(User.class).set(User::getUserName, \"base64\").where(User::getId).eq(2).execute();\n```\n\n### Delete\n\n```java\nint result = delete().from(User.class).where(\"id\", 1).execute();\n// DELETE FROM users WHERE id = ?\n```\n\nor\n\n```java\nUser user = new User();\nuser.setAge(15);\nuser.setUserName(\"jack\");\nuser.delete();\n// DELETE FROM users WHERE user_name = ? and age = ?\n```\n\n```java\ndelete().from(User.class).where(User::getId).deleteById(3);\ndelete().from(User.class).where(User::getId).eq(1).execute();\ndelete().from(User.class).where(User::getAge).lte(20).execute();\n```\n\n### Transaction\n\n```java\nAnima.atomic(() -\u003e {\n    int a = 1 / 0;\n    new User(\"apple\", 666).save();\n}).catchException(e -\u003e Assert.assertEquals(ArithmeticException.class, e.getClass()));\n```\n\n\u003e 📗 `Anima` uses the `atomic` method to complete a transaction. normally, the code will not throw an exception. \n\u003e when a `RuntimeException` is caught, the transaction will be `rollback`.\n\n## Test Code\n\nSee [here](https://github.com/biezhi/anima/tree/master/src/test/java/io/github/biezhi/anima)\n\n## License\n\n[Apache2](https://github.com/hellokaton/anima/blob/dev/LICENSE)\n","funding_links":[],"categories":["Database"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhellokaton%2Fanima","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhellokaton%2Fanima","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhellokaton%2Fanima/lists"}