Browse Source

DATAJDBC-391 - Revise readme for a consistent structure.

1.0.x
Mark Paluch 7 years ago
parent
commit
82cb0bc057
  1. 30
      CI.adoc
  2. 468
      README.adoc

30
CI.adoc

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
= Continuous Integration
image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-jdbc%2Fmaster&subject=Moore%20(master)["Spring Data JDBC", link="https://jenkins.spring.io/view/SpringData/job/spring-data-jdbc/"]
image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-jdbc%2F1.0.x&subject=Lovelace%20(1.0.x)["Spring Data JDBC", link="https://jenkins.spring.io/view/SpringData/job/spring-data-jdbc/"]
== Running CI tasks locally
Since this pipeline is purely Docker-based, it's easy to:
* Debug what went wrong on your local machine.
* Test out a a tweak to your `test.sh` script before sending it out.
* Experiment against a new image before submitting your pull request.
All of these use cases are great reasons to essentially run what the CI server does on your local machine.
IMPORTANT: To do this you must have Docker installed on your machine.
1. `docker run -it --mount type=bind,source="$(pwd)",target=/spring-data-jdbc-github -v /usr/bin/docker:/usr/bin/docker -v /var/run/docker.sock:/var/run/docker.sock adoptopenjdk/openjdk8:latest /bin/bash`
+
This will launch the Docker image and mount your source code at `spring-data-jdbc-github`.
+
2. `cd spring-data-jdbc-github`
+
Next, test everything from inside the container:
+
3. `./mvnw -Pci,all-dbs clean dependency:list test -Dsort -B` (or whatever test configuration you must use)
Since the container is binding to your source, you can make edits from your IDE and continue to run build jobs.
NOTE: Docker containers can eat up disk space fast! From time to time, run `docker system prune` to clean out old images.

468
README.adoc

@ -1,425 +1,175 @@ @@ -1,425 +1,175 @@
image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-jdbc%2Fmaster&subject=Moore%20(master)["Spring Data JDBC", link="https://jenkins.spring.io/view/SpringData/job/spring-data-jdbc/"]
image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-jdbc%2F1.0.x&subject=Lovelace%20(1.0.x)["Spring Data JDBC", link="https://jenkins.spring.io/view/SpringData/job/spring-data-jdbc/"]
image:https://spring.io/badges/spring-data-jdbc/ga.svg["Spring Data JDBC", link="https://spring.io/projects/spring-data-jdbc#learn"]
image:https://spring.io/badges/spring-data-jdbc/snapshot.svg["Spring Data JDBC", link="https://spring.io/projects/spring-data-jdbc#learn"]
= Spring Data Relational
= Spring Data JDBC image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-jdbc%2Fmaster&subject=Build[link=https://jenkins.spring.io/view/SpringData/job/spring-data-jdbc/] https://gitter.im/spring-projects/spring-data[image:https://badges.gitter.im/spring-projects/spring-data.svg[Gitter]]
== This is NOT an ORM
The primary goal of the https://projects.spring.io/spring-data[Spring Data] project is to make it easier to build Spring-powered applications that use new data access technologies such as non-relational databases, map-reduce frameworks, and cloud based data services.
Spring Data JDBC does not try to be an ORM. It is not a competitor to JPA.
Instead it is more of a construction kit for your personal ORM that you can define the way you like or need it.
Spring Data JDBC, part of the larger Spring Data family, makes it easy to implement JDBC based repositories. This module deals with enhanced support for JDBC based data access layers. It makes it easier to build Spring powered applications that use data access technologies.
This means that it does rather little out of the box.
But it offers plenty of places where you can put your own logic, or integrate it with the technology of your choice for generating SQL statements.
It aims at being conceptually easy.
In order to achieve this it does NOT offer caching, lazy loading, write behind or many other features of JPA.
This makes Spring Data JDBC a simple, limited, opinionated ORM.
== The Aggregate Root
Spring Data repositories are inspired by the repository as described in the book Domain Driven Design by Eric Evans.
One consequence of this is that you should have a repository per Aggregate Root.
Aggregate Root is another concept from the same book and describes an entity which controls the lifecycle of other entities which together are an Aggregate.
An Aggregate is a subset of your model which is consistent between method calls to your Aggregate Root.
Spring Data JDBC tries its best to encourage modelling your domain along these ideas.
== Features
== Maven Coordinates
* Implementation of CRUD methods for Aggregates.
* `@Query` annotation
* Support for transparent auditing (created, last changed)
* Events for persistence events
* Possibility to integrate custom repository code
* JavaConfig based repository configuration by introducing `EnableJdbcRepository`
* Integration with MyBatis
[source,xml]
----
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jdbc</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
</dependency>
----
== Code of Conduct
== Features
This project is governed by the link:CODE_OF_CONDUCT.adoc[Spring Code of Conduct]. By participating, you are expected to uphold this code of conduct. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
=== CRUD operations
== Getting Started
In order to use Spring Data JDBC you need the following:
Here is a quick teaser of an application using Spring Data Repositories in Java:
1. An entity with an attribute marked as _id_ using the Spring Data https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/annotation/Id.html[`@Id`] annotation.
+
[source,java]
----
public class Person {
@Id
Integer id;
}
----
+
1. A repository
+
[source,java]
----
public interface PersonRepository extends CrudRepository<Person, Integer> {}
----
+
1. Add `@EnableJdbcRepositories` to your application context configuration.
1. Make sure your application context contains a bean of type `DataSource`.
public interface PersonRepository extends CrudRepository<Person, Long> {
Now you can get an instance of the repository interface injected into your beans and use it:
[source,java]
----
@Autowired
private PersonRepository repository;
@Query("SELECT * FROM person WHERE lastname = :lastname")
List<Person> findByLastname(String lastname);
public void someMethod() {
Person person = repository.save(new Person());
@Query("SELECT * FROM person WHERE firstname LIKE :lastname")
List<Person> findByFirstnameLike(String firstname);
}
----
==== Supported types in your entity
Properties of the following types are currently supported:
* all primitive types and their boxed types (`int`, `float`, `Integer`, `Float` ...)
* enums get mapped to their name.
* `String`
* `java.util.Date`, `java.time.LocalDate`, `java.time.LocalDateTime`, `java.time.LocalTime`
and anything your database driver accepts.
@Service
public class MyService {
* references to other entities, which will be considered a one-to-one relationship.
The table of the referenced entity is expected to have an additional column named like the table of the referencing entity.
This name can be changed by implementing `NamingStrategy.getReverseColumnName(JdbcPersistentProperty property)` according to your preferences.
private final PersonRepository repository;
* `Set<some entity>` will be considered a one-to-many relationship.
The table of the referenced entity is expected to have an additional column named like the table of the referencing entity.
This name can be changed by implementing `NamingStrategy.getReverseColumnName(JdbcPersistentProperty property)` according to your preferences.
public MyService(PersonRepository repository) {
this.repository = repository;
}
* `Map<simple type, some entity>` will be considered a qualified one-to-many relationship.
The table of the referenced entity is expected to have two additional columns: One named like the table of the referencing entity for the foreign key and one with the same name and an additional `_key` suffix for the map key.
This name can be changed by implementing `NamingStrategy.getReverseColumnName(JdbcPersistentProperty property)` and `NamingStrategy.getKeyColumn(JdbcPersistentProperty property)` according to your preferences.
public void doWork() {
* `List<some entity>` will be mapped like a `Map<Integer, some entity>`.
The handling of referenced entities is very limited.
Part of this is because this project is still before its first release.
But another reason is the idea of <<The Aggregate Root,Aggregate Roots>> as described above.
If you reference another entity that entity is by definition part of your Aggregate.
So if you remove the reference it will get deleted.
This also means references will be 1-1 or 1-n, but not n-1 or n-m.
If you are having n-1 or n-m references you are probably dealing with two separate Aggregates.
References between those should be encoded as simple ids, which should map just fine with Spring Data JDBC.
Also the mapping we offer is very limited for a third reason which already was mentioned at the very beginning of the document: this is not an ORM.
We will offer ways to plug in your own SQL in various ways.
But the default mapping itself will stay limited.
If you want highly customizable mappings which support almost everything one can imagine you will probably be much happier with (Spring Data) JPA,
which is a very powerful and mature technology.
=== Query annotation
You can annotate a query method with `@Query` to specify a SQL statement to be used for that method.
You can bind method arguments using named parameters in the SQL statement like in the following example:
[source,java]
----
@Query("SELECT * FROM DUMMYENTITY WHERE name < :upper and name > :lower")
List<DummyEntity> findByNameRange(@Param("lower") String lower, @Param("upper") String upper);
----
repository.deleteAll();
If you compile your sources with the `-parameters` compiler flag you can omit the `@Param` annotations.
Person person = new Person();
person.setFirstname("Jens");
person.setLastname("Schauder");
repository.save(person);
==== Custom RowMapper
List<Person> lastNameResults = repository.findByLastname("Schauder");
List<Person> firstNameResults = repository.findByFirstnameLike("Je%");
}
}
You can configure the `RowMapper` to use, using either the `@Query(rowMapperClass = ....)` or you can register a `RowMapperMap` bean and register `RowMapper` per method return type.
@Configuration
@EnableJdbcRepositories
class ApplicationConfig extends AbstractJdbcConfiguration {
[source,java]
----
@Bean
public DataSource dataSource() {
return …;
}
@Bean
RowMapperMap rowMappers() {
return new ConfigurableRowMapperMap() //
.register(Person.class, new PersonRowMapper()) //
.register(Address.class, new AddressRowMapper());
@Bean
public NamedParameterJdbcTemplate namedParameterJdbcTemplate(DataSource dataSource) {
return new NamedParameterJdbcTemplate(dataSource);
}
}
----
When determining the `RowMapper` to use for a method the following steps are followed based on the return type of the method:
1. If the type is a simple type, no `RowMapper` is used.
Instead the query is expected to return a single row with a single column and a conversion to the return type is applied to that value.
=== Maven configuration
2. The entity classes in the `RowMapperMap` are iterated until one is found that is a superclass or interface of the return type in question.
The `RowMapper` registered for that class is used.
Iterating happens in the order of registration, so make sure to register more general types after specific ones.
Add the Maven dependency:
If applicable, wrapper types like collections or `Optional` are unwrapped.
Thus, a return type of `Optional<Person>` will use the type `Person` in the steps above.
==== Modifying query
You can mark as a modifying query using the `@Modifying` on query method.
[source,java]
[source,xml]
----
@Modifying
@Query("UPDATE DUMMYENTITY SET name = :name WHERE id = :id")
boolean updateName(@Param("id") Long id, @Param("name") String name);
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jdbc</artifactId>
<version>${version}.RELEASE</version>
</dependency>
----
The return types that can be specified are `void`, `int`(updated record count) and `boolean`(whether record was updated).
=== Id generation
If you'd rather like the latest snapshots of the upcoming major version, use our Maven snapshot repository and declare the appropriate dependency version.
Spring Data JDBC uses the id to identify entities, but also to determine if an entity is new or already existing in the database.
If the id is `null` or of a primitive type having value `0` or `0.0`, the entity is considered new.
If your database has some autoincrement-column for the id-column, the generated value will get set in the entity after inserting it into the database.
There are few ways to tweak this behavior.
If you don't like the logic to distinguish between new and existing entities you can implement https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/Persistable.html[`Persistable`] with your entity and overwrite `isNew()` with your own logic.
One important constraint is that after saving an entity the entity shouldn't be _new_ anymore.
With autoincrement-columns this happens automatically since the id gets set by Spring Data with the value from the id-column.
If you are not using autoincrement-columns, you can use a `BeforeSave`-listener which sets the id of the entity (see below).
=== NamingStrategy
If you use the standard implementations of `CrudRepository` as provided by Spring Data JDBC, it will expect a certain table structure.
You can tweak that by providing a https://github.com/spring-projects/spring-data-jdbc/blob/master/src/main/java/org/springframework/data/jdbc/mapping/model/NamingStrategy.java[`NamingStrategy`] in your application context.
In many cases a https://github.com/spring-projects/spring-data-jdbc/blob/master/src/main/java/org/springframework/data/jdbc/mapping/model/DelimiterNamingStrategy.java[`DelimiterNamingStrategy`]
might be good basis for a custom implementation
=== Events
Spring Data JDBC triggers events which will get published to any matching `ApplicationListener` in the application context.
For example, the following listener will get invoked before an Aggregate gets saved.
[source,java]
[source,xml]
----
@Bean
public ApplicationListener<BeforeSaveEvent> timeStampingSaveTime() {
return event -> {
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jdbc</artifactId>
<version>${version}.BUILD-SNAPSHOT</version>
</dependency>
Object entity = event.getEntity();
if (entity instanceof Category) {
Category category = (Category) entity;
category.timeStamp();
}
};
}
<repository>
<id>spring-libs-snapshot</id>
<name>Spring Snapshot Repository</name>
<url>https://repo.spring.io/libs-snapshot</url>
</repository>
----
.Available events
|===
| Event | When It's Published
| https://github.com/spring-projects/spring-data-jdbc/blob/master/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeDeleteEvent.java[`BeforeDeleteEvent`]
| before an aggregate root gets deleted.
| https://github.com/spring-projects/spring-data-jdbc/blob/master/src/main/java/org/springframework/data/jdbc/mapping/event/AfterDeleteEvent.java[`AfterDeleteEvent`]
| after an aggregate root got deleted.
| https://github.com/spring-projects/spring-data-jdbc/blob/master/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeSaveEvent.java[`BeforeSaveEvent`]
| before an aggregate root gets saved, i.e. inserted or updated but after the decision was made if it will get updated or deleted.
The event has a reference to an https://github.com/spring-projects/spring-data-jdbc/blob/master/src/main/java/org/springframework/data/jdbc/core/conversion/AggregateChange.java[`AggregateChange`] instance.
The instance can be modified by adding or removing https://github.com/spring-projects/spring-data-jdbc/blob/master/src/main/java/org/springframework/data/jdbc/core/conversion/DbAction.java[`DbAction`]s.
| https://github.com/spring-projects/spring-data-jdbc/blob/master/src/main/java/org/springframework/data/jdbc/mapping/event/AfterSaveEvent.java[`AfterSaveEvent`]
| after an aggregate root gets saved, i.e. inserted or updated.
| https://github.com/spring-projects/spring-data-jdbc/blob/master/src/main/java/org/springframework/data/jdbc/mapping/event/AfterLoadEvent.java[`AfterLoadEvent`]
| after an aggregate root got created from a database `ResultSet` and all it's property set
|===
=== MyBatis
For each operation in `CrudRepository` Spring Data JDBC will execute multiple statements.
If there is a https://github.com/mybatis/mybatis-3/blob/master/src/main/java/org/apache/ibatis/session/SqlSessionFactory.java[`SqlSessionFactory`] in the application context, it will be checked if it offers a statement for each step.
If one is found, that statement will be used (including its configured mapping to an entity).
By default, the name of the statement is constructed by concatenating the fully qualified name of the entity type with `Mapper.` and a string determining the kind of statement.
E.g. if an instance of `org.example.User` is to be inserted, Spring Data JDBC will look for a statement named `org.example.UserMapper.insert`.
Upon execution of the statement an instance of [`MyBatisContext`] will get passed as an argument which makes various arguments available to the statement.
[cols="default,default,default,asciidoc"]
|===
| Name | Purpose | CrudRepository methods which might trigger this statement | Attributes available in the `MyBatisContext`
| `insert` | Insert for a single entity. This also applies for entities referenced by the aggregate root. | `save`, `saveAll`. |
`getInstance`:
the instance to be saved
`getDomainType`: the type of the entity to be saved.
`get(<key>)`: id of the referencing entity, where `<key>` is the name of the back reference column as provided by the `NamingStrategy`.
| `update` | Update for a single entity. This also applies for entities referenced by the aggregate root. | `save`, `saveAll`.|
`getInstance`: the instance to be saved
`getDomainType`: the type of the entity to be saved.
| `delete` | Delete a single entity. | `delete`, `deleteById`.|
`getId`: the id of the instance to be deleted
`getDomainType`: the type of the entity to be deleted.
| `deleteAll.<propertyPath>` | Delete all entities referenced by any aggregate root of the type used as prefix via the given property path.
Note that the type used for prefixing the statement name is the name of the aggregate root, not the one of the entity to be deleted. | `deleteAll`.|
`getDomainType`: the type of the entities to be deleted.
| `deleteAll` | Delete all aggregate roots of the type used as the prefix | `deleteAll`.|
`getDomainType`: the type of the entities to be deleted.
| `delete.<propertyPath>` | Delete all entities referenced by an aggregate root via the given propertyPath | `deleteById`.|
`getId`: the id of the aggregate root for which referenced entities are to be deleted.
`getDomainType`: the type of the entities to be deleted.
| `findById` | Select an aggregate root by id | `findById`.|
`getId`: the id of the entity to load.
`getDomainType`: the type of the entity to load.
| `findAll` | Select all aggregate roots | `findAll`.|
`getDomainType`: the type of the entity to load.
| `findAllById` | Select a set of aggregate roots by ids | `findAllById`.|
`getId`: list of ids of the entities to load.
`getDomainType`: the type of the entity to load.
| `findAllByProperty.<propertyName>` | Select a set of entities that is referenced by another entity. The type of the referencing entity is used for the prefix. The referenced entities type as the suffix. | All `find*` methods.|
`getId`: the id of the entity referencing the entities to be loaded.
`getDomainType`: the type of the entity to load.
| `count` | Count the number of aggregate root of the type used as prefix | `count` |
`getDomainType` the type of aggregate roots to count.
|===
==== NamespaceStrategy
You can customize the namespace part of a statement name using https://github.com/spring-projects/spring-data-jdbc/blob/master/src/main/java/org/springframework/data/jdbc/mybatis/NamespaceStrategy.java[`NamespaceStrategy`].
== Features planned for the not too distant future
=== Advanced query annotation support
* projections
* SpEL expressions
=== MyBatis per method support
The current MyBatis supported is rather elaborate in that it allows to execute multiple statements for a single method call.
But sometimes less is more, and it should be possible to annotate a method with a simple annotation to identify a SQL statement in a MyBatis mapping to be executed.
== Spring Boot integration
There is https://github.com/schauder/spring-data-jdbc-boot-starter[preliminary Spring Boot integration].
Currently you will need to build it locally.
== Getting Help
Right now the best source of information is the source code in this repository.
Especially the integration tests (if you are reading this on github, type `t` and then `IntegrationTests.java`)
We are keeping an eye on the https://stackoverflow.com/questions/tagged/spring-data-jdbc[spring-data-jdbc tag on stackoverflow].
Having trouble with Spring Data? We’d love to help!
If you think you found a bug, or have a feature request please https://jira.spring.io/browse/DATAJDBC/?selectedTab=com.atlassian.jira.jira-projects-plugin:summary-panel[create a ticket in our issue tracker].
* If you are new to Spring Data JDBC read the following two articles https://spring.io/blog/2018/09/17/introducing-spring-data-jdbc["Introducing Spring Data JDBC"] and https://spring.io/blog/2018/09/24/spring-data-jdbc-references-and-aggregates["Spring Data JDBC, References, and Aggregates"].
* Check the
https://docs.spring.io/spring-data/jdbc/docs/current/reference/html/[reference documentation], and https://docs.spring.io/spring-data/jdbc/docs/current/api/[Javadocs].
* Learn the Spring basics – Spring Data builds on Spring Framework, check the https://spring.io[spring.io] web-site for a wealth of reference documentation.
If you are just starting out with Spring, try one of the https://spring.io/guides[guides].
* If you are upgrading, check out the https://docs.spring.io/spring-data/jdbc/docs/current/changelog.txt[changelog] for "`new and noteworthy`" features.
* Ask a question - we monitor https://stackoverflow.com[stackoverflow.com] for questions tagged with https://stackoverflow.com/tags/spring-data[`spring-data-jdbc`].
You can also chat with the community on https://gitter.im/spring-projects/spring-data[Gitter].
* Report bugs with Spring Data JDBC at https://jira.spring.io/browse/DATAJDBC[jira.spring.io/browse/DATAJDBC].
== Execute Tests
== Reporting Issues
=== Fast running tests
Fast running tests can be executed with a simple
[source]
----
mvn test
----
Spring Data uses JIRA as issue tracking system to record bugs and feature requests. If you want to raise an issue, please follow the recommendations below:
This will execute unit tests and integration tests using an in-memory database.
* Before you log a bug, please search the
https://jira.spring.io/browse/DATAJDBC[issue tracker] to see if someone has already reported the problem.
* If the issue doesn’t already exist, https://jira.spring.io/browse/DATAJDBC[create a new issue].
* Please provide as much information as possible with the issue report, we like to know the version of Spring Data that you are using and JVM version.
* If you need to paste code, or include a stack trace use JIRA `{code}…{code}` escapes before and after your text.
* If possible try to create a test-case or project that replicates the issue. Attach a link to your code or a compressed file containing your code.
=== Running tests with a real database
== Building from Source
In order to run the integration tests against a specific database you need to have a local Docker installation available, and then execute.
You don’t need to build from source to use Spring Data (binaries in https://repo.spring.io[repo.spring.io]), but if you want to try out the latest and greatest, Spring Data can be easily built with the https://github.com/takari/maven-wrapper[maven wrapper].
You also need JDK 1.8.
[source]
[source,bash]
----
mvn test -Dspring.profiles.active=<databasetype>
$ ./mvnw clean install
----
This will also execute the unit tests.
If you want to build with the regular `mvn` command, you will need https://maven.apache.org/run-maven/index.html[Maven v3.5.0 or above].
Currently the following _databasetypes_ are available:
_Also see link:CONTRIBUTING.adoc[CONTRIBUTING.adoc] if you wish to submit pull requests, and in particular please sign the https://cla.pivotal.io/sign/spring[Contributor’s Agreement] before your first change, is trivial._
* hsql (default, does not require a running database)
* mysql
* postgres
* mariadb
=== Building reference documentation
=== Run tests with all databases
Building the documentation builds also the project without running tests.
[source]
[source,bash]
----
mvn test -Pall-dbs
$ ./mvnw clean install -Pdistribute
----
This will execute the unit tests, and all the integration tests with all the databases we currently support for testing. Running the integration-tests depends on Docker.
== Running CI tasks locally
Since this pipeline is purely Docker-based, it's easy to:
* Debug what went wrong on your local machine.
* Test out a a tweak to your `test.sh` script before sending it out.
* Experiment against a new image before submitting your pull request.
All of these use cases are great reasons to essentially run what the CI server does on your local machine.
IMPORTANT: To do this you must have Docker installed on your machine.
1. `docker run -it --mount type=bind,source="$(pwd)",target=/spring-data-jdbc-github -v /usr/bin/docker:/usr/bin/docker -v /var/run/docker.sock:/var/run/docker.sock adoptopenjdk/openjdk8:latest /bin/bash`
+
This will launch the Docker image and mount your source code at `spring-data-jdbc-github`.
+
2. `cd spring-data-jdbc-github`
+
Next, test everything from inside the container:
+
3. `./mvnw -Pci,all-dbs clean dependency:list test -Dsort -B` (or whatever test configuration you must use)
Since the container is binding to your source, you can make edits from your IDE and continue to run build jobs.
The generated documentation is available from `target/site/reference/html/index.html`.
NOTE: Docker containers can eat up disk space fast! From time to time, run `docker system prune` to clean out old images.
== Modules
== Contributing to Spring Data Relational
There are a number of modules in this project, here is a quick overview:
Here are some ways for you to get involved in the community:
* Spring Data Relational: Common infrastructure abstracting general aspects of relational database access.
* link:spring-data-jdbc[Spring Data JDBC]: Repository support for JDBC-based datasources.
* Get involved with the Spring community by helping out on https://stackoverflow.com/questions/tagged/spring-data-jdbc[stackoverflow] by responding to questions and joining the debate.
* Create https://jira.spring.io/browse/DATAJDBC[JIRA] tickets for bugs and new features and comment and vote on the ones that you are interested in.
* Github is for social coding: if you want to write code, we encourage contributions through pull requests from https://help.github.com/forking/[forks of this repository]. If you want to contribute code this way, please reference a JIRA ticket as well, covering the specific issue you are addressing.
* Watch for upcoming articles on Spring by https://spring.io/blog[subscribing] to spring.io.
== Examples
Before we accept a non-trivial patch or pull request we will need you to https://cla.pivotal.io/sign/spring[sign the Contributor License Agreement]. Signing the contributor’s agreement does not grant anyone commit rights to the main repository, but it does mean that we can accept your contributions, and you will get an author credit if we do. If you forget to do so, you'll be reminded when you submit a pull request. Active contributors might be asked to join the core team, and given the ability to merge pull requests.
* https://github.com/spring-projects/spring-data-examples/[Spring Data Examples] contains example projects that explain specific features in more detail.
== License
link:src/main/resources/license.txt[The license under which Spring Data JDBC is published can be found here].
Spring Data JDBC is Open Source software released under the https://www.apache.org/licenses/LICENSE-2.0.html[Apache 2.0 license].

Loading…
Cancel
Save